Base64 verilerini ayrıştırmak veya doğrulamak için RegEx


100

Base64 verilerini doğrulamak veya sterilize etmek için bir RegEx kullanmak mümkün müdür? Basit soru bu, ancak bu soruyu yönlendiren faktörler onu zorlaştıran şeydir.

RFC özelliklerini takip etmek için giriş verilerine tam olarak güvenemeyen bir Base64 kod çözücüm var. Bu yüzden, karşılaştığım sorunlar, belki Base64 verileri gibi 78'e bölünemeyen sorunlar (78 olduğunu düşünüyorum, RFC'yi iki kez kontrol etmem gerekecek, bu yüzden tam sayı yanlışsa beni ding etme) karakter satırlar veya satırların CRLF ile bitmeyebileceğini; sadece bir CR veya LF'ye sahip olabilir veya ikisi de olmayabilir.

Yani, bu şekilde biçimlendirilmiş Base64 verilerini ayrıştırırken çok zaman geçirdim. Bu nedenle, aşağıdaki gibi örneklerin güvenilir bir şekilde çözülmesi imkansız hale gelir. Kısaca sadece kısmi MIME başlıklarını göstereceğim.

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Tamam, bu yüzden ayrıştırmak sorun değil ve tam da beklediğimiz sonuç. Ve vakaların% 99'unda, en azından arabellekteki her bir karakterin geçerli bir base64 karakter olduğunu doğrulamak için herhangi bir kod kullanmak mükemmel çalışıyor. Ancak, bir sonraki örnek karışıma bir anahtar fırlatıyor.

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Bu, bazı virüslerde ve bazı posta okuyucularından yararlanmaya çalışan bazı diğer şeylerde gördüğüm bir Base64 kodlama sürümü, kesinlikle kitaba veya daha doğrusu RFC'ye göre, her ne pahasına olursa olsun mime ayrıştırmak istiyor; eğer yapacaksan.

Base64 kod çözücüm, ikinci örneği aşağıdaki veri akışına çözer. Ve burada unutmayın, orijinal akışın tüm ASCII verileri!

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

Her iki sorunu da aynı anda çözmenin iyi bir yolu olan var mı? Farklı kurallar uygulanarak veriler üzerinde iki dönüşüm yapmak ve sonuçları karşılaştırmak dışında bunun mümkün olduğundan bile emin değilim. Ancak bu yaklaşımı benimserseniz, hangi çıktıya güvenirsiniz? Görünüşe göre ASCII buluşsal yöntemi en iyi çözümle ilgilidir, ancak bu, bu kodun gerçekte dahil olduğu bir virüs tarayıcısı kadar karmaşık bir şeye ne kadar daha fazla kod, yürütme süresi ve karmaşıklık ekler? Base64'ün kabul edilebilir olup olmadığını öğrenmek için sezgisel motoru nasıl eğitirsiniz?


GÜNCELLEME:

Bu sorunun almaya devam ettiği görünümlerin sayısını yapın, 3 yıldır bir C # uygulamasında kullandığım basit RegEx'i yüz binlerce işlemle göndermeye karar verdim. Dürüst olmak gerekirse, Gumbo'nun verdiği cevabı en çok beğendim , bu yüzden onu seçilen cevap olarak seçtim. Ancak C # kullanan ve en azından bir dizenin veya baytın [] geçerli Base64 verisi içerip içermediğini tespit etmenin çok hızlı bir yolunu arayanlar için, aşağıdakilerin benim için çok iyi çalıştığını buldum.

[^-A-Za-z0-9+/=]|=[^=]|={3,}$

Ve evet, bu sadece bir içindir STRING Base64 verilerine DEĞİL düzgün şekilde biçimlendirilmiş bir RFC1341 mesajının. Bu nedenle, bu tür verilerle uğraşıyorsanız, lütfen yukarıdaki Normal İfadeyi kullanmaya çalışmadan önce bunu dikkate alın. Eğer Base16, Base32, Radix veya diğer amaçlarla (URL'ler, dosya adları, XML Kodlama, vs.) için bile Base64 ile ilgileniyor, o zaman olduğu son derece okumak öneririz RFC4648 o Bamya iyi olması gerekir olarak onun cevapta belirtildiği Bu soru / cevap setindeki önerileri kullanmaya başlamadan önce uygulama tarafından kullanılan karakter seti ve sonlandırıcıların farkında olmak.


Sanırım görevi daha iyi tanımlaman gerekiyor. Amacınızın ne olduğu tamamen belirsiz: katı olmak? örneklerin% 100'ü ayrıştırılsın mı? ...
ADEpt

İlk örnek 'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4 ='
jfs

Neden kendi dilinizde standart bir çözüm kullanmıyorsunuz? Neden düzenli ifadelere dayalı olarak elle yazılmış ayrıştırıcıya ihtiyacınız var?
jfs

1
Harika soru. UPDATE regex'i NPM tarafından döndürülen base64 kodlu bir SHA'ya karşı çalıştırarak denedim ve başarısız oldu, oysa seçilen yanıttaki normal ifade gayet iyi çalışıyor .
Josh Habdas

1
Değil emin nasıl GÜNCELLEME regex hala düzeltme olmadan yayınlanmıştır, ancak yazar gibi görünüyor anlamına koymak için ^bir başlangıç çapa olarak, parantez dışında. Ancak, kabul edilen cevap kadar karmaşıklaşmadan çok daha iyi bir normal ifade şu olurdu^[-A-Za-z0-9+/]*={0,3}$
kael

Yanıtlar:


149

Gönderen 4648 RFC :

Verilerin temel kodlaması, birçok durumda verileri, belki de eski nedenlerden dolayı US-ASCII verileriyle sınırlı olan ortamlarda depolamak veya aktarmak için kullanılır.

Dolayısıyla, verilerin tehlikeli olarak değerlendirilip değerlendirilmeyeceği, kodlanan verilerin kullanım amacına bağlıdır.

Ancak, Base64 kodlu sözcüklerle eşleşecek bir normal ifade arıyorsanız, aşağıdakileri kullanabilirsiniz:

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$

10
En basit çözüm, doğrulamadan önce tüm boşlukları (RFC'ye göre yok sayılır) çıkarmak olacaktır.
Ben Blank

2
Dolgu için yakalamayan son grup isteğe bağlıdır.
Gumbo

4
İlk başta karmaşıklık konusunda şüpheliydim, ancak oldukça iyi doğruluyor. Sadece base64-ish ile eşleştirmek isterseniz ^ [a-zA-Z0-9 + /] = {0,3} $ yapmayı düşünürdüm, bu daha iyi!
Lodewijk

3
@BogdanNechyporenko Bunun nedeni name(hex) bayt dizisinin geçerli bir Base64 kodlaması olmasıdır 9d a9 9e.
Marten

3
^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$geri
tepmeden kaçmalı

38
^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$

Bu iyi, ancak boş bir String ile eşleşecek

Bu, boş dizeyle eşleşmiyor:

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$

2
Boş dizge neden geçersizdir?
Josh Lee

8
o değil. ancak belirli bir dizenin base64 olup olmadığını öğrenmek için bir normal ifade kullanıyorsanız, büyük olasılıkla boş dizelerle ilgilenmiyorsunuzdur. En azından olmadığımı biliyorum.
njzk2

4
@LayZee: Bunu yaparsanız, base64 dizesini en az 4 boyutlu bir blok MQ==
içermeye zorlarsınız

5
@ruslan ne de yapmamalı. bu geçerli bir temel 64 dizesi değil. (boyut 23'tür, // 4 değildir). AQENVg688MSGlEgdOJpjIUC=geçerli formdur.
njzk2

1
@JinKwon base64 0, 1 veya 2 ile biter =. Sonuncusu ?0'a izin verir =. {1}=
İle

4

Geçerli Base64'te ne bir " : " ne de bir " . " Görünmeyecek, bu yüzden açıkça http://www.stackoverflow.comsatırı atabileceğinizi düşünüyorum . Perl'de şöyle bir şey söyle

my $sanitized_str = join q{}, grep {!/[^A-Za-z0-9+\/=]/} split /\n/, $str;

say decode_base64($sanitized_str);

istediğin şey olabilir. Ürettiği

Bu, StackOverflow örneği için basit ASCII Base64'tür.


Orada kabul edebilirim, ancak URL'deki tüm DİĞER harfler geçerli base64 oluyor ... Peki, çizgiyi nereye çekiyorsunuz? Sadece satır sonlarında mı? (Çizginin ortasında sadece birkaç rasgele karakter var nerede olduğunu olanları gördük sırf IMHO hattının geri kalanını atmak olamaz.) ...
LarryF

@LarryF: Temel 64 kodlanmış verilerde bütünlük denetimi olmadığı sürece, yanlış karakterler içeren herhangi bir temel 64 veri bloğu ile ne yapılacağını söyleyemezsiniz. En iyi buluşsal yöntem hangisidir: Yanlış karakterleri görmezden gelmek (herhangi bir ve tüm doğru olanlara izin vermek) veya satırları reddetmek veya partiyi reddetmek?
Jonathan Leffler

(devam): Kısa cevap "bağlıdır" - verilerin nereden geldiğine ve içinde bulduğunuz karışıklık türlerine bağlıdır.
Jonathan Leffler

(devam etti): Yorumlardan soruya 64 tabanlı olabilecek herhangi bir şeyi kabul etmek istediğinizi görüyorum. Yeni satırlar ve iki nokta üst üste işaretleri dahil olmak üzere temel 64 alfabenizde olmayan her karakteri (URL güvenli ve bu tür başka değişken kodlamaları olduğunu unutmayın) basitçe eşleyin ve kalanları alın.
Jonathan Leffler

4

Şimdiye kadar bulabildiğim en iyi regexp burada https://www.npmjs.com/package/base64-regex

mevcut sürümde olan şu şekilde görünür:

module.exports = function (opts) {
  opts = opts || {};
  var regex = '(?:[A-Za-z0-9+\/]{4}\\n?)*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)';

  return opts.exact ? new RegExp('(?:^' + regex + '$)') :
                    new RegExp('(?:^|\\s)' + regex, 'g');
};

Olmadan belki daha iyi \\n?.
Jin Kwon

Bu JSON dizelerinde başarısız olacak
idleberg

3

Base64 görüntüsünü doğrulamak için bu regex'i kullanabiliriz

/ ^ data: image / (?: gif | png | jpeg | bmp | webp) (?:; charset = utf-8) ?; base64, (?: [A-Za-z0-9] | [+ /] ) + = {0,2}

  private validBase64Image(base64Image: string): boolean {
    const regex = /^data:image\/(?:gif|png|jpeg|bmp|webp)(?:;charset=utf-8)?;base64,(?:[A-Za-z0-9]|[+/])+={0,2}/;
    return base64Image && regex.test(base64Image);
  }

0

İşte alternatif bir normal ifade:

^(?=(.{4})*$)[A-Za-z0-9+/]*={0,2}$

Aşağıdaki koşulları karşılar:

  • Dize uzunluğu dörtten katı olmalıdır - (?=^(.{4})*$)
  • İçerik alfanümerik karakterler veya + veya / - olmalıdır [A-Za-z0-9+/]*
  • Sonunda en fazla iki dolgu (=) karakteri olabilir - ={0,2}
  • Boş dizeleri kabul eder

0

Şimdiye kadar sunulan cevaplar, Base64 dizgisinin tüm ped bitlerinin 0'a ayarlandığını kontrol edemiyor, çünkü bunun Base64'ün kanonik temsili olması gerekiyor (bu bazı ortamlarda önemlidir, bkz. Https://tools.ietf.org/ html / rfc4648 # bölüm-3.5 ) ve bu nedenle, aynı ikili dizge için farklı kodlamalar olan diğer adlara izin verirler . Bu, bazı uygulamalarda bir güvenlik sorunu olabilir.

Verilen dizenin yalnızca geçerli base64 olmadığını, aynı zamanda ikili veriler için kanonik base64 dizesi olduğunu doğrulayan normal ifade şöyledir:

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/][AQgw]==|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=)?$

Alıntı yapılan RFC boş dizeyi geçerli kabul eder (bkz. Https://tools.ietf.org/html/rfc4648#section-10 ), bu nedenle yukarıdaki normal ifade de geçerlidir.

Base64url için eşdeğer normal ifade (yine yukarıdaki RFC'ye bakın):

^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-][AQgw]==|[A-Za-z0-9_-]{2}[AEIMQUYcgkosw048]=)?$
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.