Base64データを解析または検証するRegEx


99

RegExを使用してBase64データを検証またはサニタイズすることは可能ですか?それは簡単な質問ですが、この質問を駆り立てる要因はそれを困難にするものです。

私は、RFC仕様に従うために入力データに完全に依存することができないBase64デコーダーを持っています。したがって、私が直面している問題は、おそらくBase64データのように78に分割されない可能性がある問題です(78だと思います。RFCを再確認する必要があるので、正確な数値が間違っていても、私に指示しないでください)。行、または行がCRLFで終わっていない可能性があります。CRまたはLFのみの場合もあれば、どちらもない場合もあります。

そのため、このようにフォーマットされたBase64データを解析するのに時間を費やしました。これにより、次のような例では確実にデコードできなくなります。簡潔にするために、MIMEヘッダーの一部のみを表示します。

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

わかりました、それで問題ない構文解析は、そしてまさに私たちが期待する結果です。また、99%の場合、コードを使用して、少なくともバッファー内の各文字が有効なbase64文字であることを確認すると、完全に機能します。しかし、次の例では、レンチを混ぜ合わせます。

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

これは、一部のウイルスやその他のメールリーダーでMIMEを解析しようとする一部のウイルスやその他のもので見られたBase64エンコーディングのバージョンです。もしそうなら。

私のBase64デコーダーは、2番目の例を次のデータストリームにデコードします。ここで、元のストリームはすべてASCIIデータであることに注意してください。

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

誰もが両方の問題を一度に解決する良い方法を持っていますか?異なるルールが適用されたデータに対して2つの変換を実行し、結果を比較する以外に、それが可能かどうかさえわかりません。しかし、そのアプローチをとった場合、どの出力を信頼しますか?ASCIIヒューリスティックスが最善の解決策であるように見えますが、このコードが実際に関与しているウイルススキャナーのような複雑なものに、コード、実行時間、および複雑さがどれほど追加されるでしょうか。どのようにしてヒューリスティックエンジンをトレーニングして、許容可能なBase64とそうでないものを学習しますか?


更新:

この質問が引き続き取得するビューの数に応じて、C#アプリケーションで3年間使用してきた数十万トランザクションの単純なRegExを投稿することにしました。正直、ガンボの答えが一番好きなので、それを選んだのです。しかし、C#を使用していて、少なくとも文字列またはbyte []に​​有効なBase64データが含まれているかどうかを検出するための非常に迅速な方法を探している人にとって、私は次のことがうまく機能することがわかりました。

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

そして、はい、これはBase64データのSTRINGのためのものであり、適切にフォーマットされたRFC1341メッセージではありません。したがって、このタイプのデータを処理する場合は、上記のRegExを使用する前にそのことを考慮してください。Base16、Base32、Radix、またはBase64を他の目的(URL、ファイル名、XMLエンコーディングなど)で扱う場合は、Gumboが彼の回答で述べたRFC4648を読むことを強くお勧めします。この質問/回答セットの提案を使用する前に、実装で使用される文字セットとターミネータを認識してください。


タスクをより明確に定義する必要があると思います。あなたの目的は何なのか完全に不明確です:厳格ですか?サンプルの100%を解析しますか?...
ADEpt 2009年

最初の例は 'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4 ='
jfs

言語で標準ソリューションを使用しないのはなぜですか?なぜ正規表現に基づく手書きのパーサーが必要なのですか?
JFS

1
すばらしい質問です。NPMから返されたbase64でエンコードされたSHAに対して実行してUPDATE正規表現を試しましたが、失敗しましたが、選択した回答の正規表現はうまく機能します
ジョシュハブダス

1
UPDATE正規表現が修正なしでどのように投稿されているかはわかりませんが、作成者が括弧の外側を開始アンカーとして配置すること意図していたよう^です。ただし、受け入れられた回答ほど複雑にならない、はるかに優れた正規表現は次のようになります^[-A-Za-z0-9+/]*={0,3}$
kael

回答:


145

RFC 4648から:

データの基本エンコードは、おそらくレガシーの理由でUS-ASCIIデータに制限されている環境でデータを格納または転送するために、多くの状況で使用されます。

したがって、データが危険であると見なされるべきかどうかは、エンコードされたデータの使用目的に依存します。

しかし、Base64でエンコードされた単語に一致する正規表現を探しているだけの場合は、次のように使用できます。

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

10
最も簡単な解決策は、検証前にすべての空白(RFCでは無視される)を取り除くことです。
ベンブランク

2
パディングの最後の非キャプチャグループはオプションです。
ガンボ2013

4
最初はその複雑さに懐疑的でしたが、それは非常によく検証されています。base64っぽいと一致させたい場合は、^ [a-zA-Z0-9 + /] = {0,3} $を実行すると思いますが、これはより良い方法です!
Lodewijk 2014

3
@BogdanNechyporenko nameは、が(16進)バイトシーケンスの有効なBase64エンコーディングであるためです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})$バックラッシュから逃れる必要があります
khizarは

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

これは良いですが、空の文字列と一致します

これは空の文字列と一致しません:

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

2
空の文字列が無効なのはなぜですか?
ジョシュリー

8
そうではない。しかし、特定の文字列がbase64かどうかを調べるために正規表現を使用している場合は、空の文字列に興味がない可能性があります。少なくとも私はそうではありません。
njzk2

4
@LayZee:そうする場合、base64文字列に少なくとも4サイズのブロックを含めるように強制MQ==し、式と一致しないなどの有効な値をレンダリングします
njzk2

5
@ruslanもすべきではない。これは有効なbase 64文字列ではありません。(サイズは23、これは// 4ではありません)。AQENVg688MSGlEgdOJpjIUC=有効なフォームです。
njzk2

1
@JinKwon base64は0、1、または2で終わります=。最後?は0を許可します=。それを置き換えるには{1}、1または2の末尾が必要です=
njzk2

4

" "も " "も有効なBase64には表示されないため、http://www.stackoverflow.com行を明確に破棄できると思います。Perlでは、たとえば、

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

say decode_base64($sanitized_str);

あなたが望むものかもしれません。それは作り出す

これはStackOverflow exmapleの単純なASCII Base64です。


私はそこに同意できますが、URLの他のすべての文字はたまたま有効なbase64です...では、どこに線を引きますか?改行だけですか?(ラインの途中にランダムな文字が2つだけあるものを見たことがあります。それが原因で、ラインの残りを投げることはできません、
IMHO

@LarryF:base-64でエンコードされたデータの整合性チェックがない限り、不正な文字を含むbase-64データブロックの処理方法を判断することはできません。どちらが最善のヒューリスティックですか。不正な文字を無視して(ありとあらゆる文字を正しく許可して)、行を拒否しますか、それともロットを拒否しますか?
ジョナサンレフラー

(続き):短い答えは「それは依存する」です-データがどこから来ているか、そしてあなたがそれで見つける混乱の種類に依存します。
ジョナサンレフラー

(再開):コメントから、base-64である可能性のあるものは何でも受け入れたいという質問が表示されます。したがって、改行やコロンを含め、base-64アルファベットにないすべての文字(URLセーフおよびその他のそのようなバリアントエンコーディングがあることに注意してください)をマッピングし、残っているものを取ります。
ジョナサンレフラー

3

私が今までに見つけた最高の正規表現はここにあり ますhttps://www.npmjs.com/package/base64-regex

現在のバージョンでは次のようになります。

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');
};

多分なし\\n?
ジンクォン

これはJSON文字列では失敗します
idleberg

3

base64イメージを検証するには、次の正規表現を使用できます

/ ^ 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);
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.