Base64 データを解析または検証する RegEx
-
19-08-2019 - |
質問
RegEx を使用して Base64 データを検証またはサニタイズすることはできますか?これは単純な質問ですが、この質問を引き起こす要因が問題を難しくしています。
私が使用している Base64 デコーダは、RFC 仕様に準拠するために入力データに完全に依存することができません。したがって、私が直面している問題は、おそらく Base64 データが 78 に分割されていない可能性があるという問題です (78 だと思います。RFC を再確認する必要があるので、正確な数字が間違っていても私を責めないでください)。行、または行が CRLF で終わっていない可能性があること。CR または LF のみを持つ場合もあれば、どちらも持たない場合もあります。
そのため、そのようにフォーマットされた Base64 データを解析するのに非常に時間がかかりました。このため、次のような例は確実にデコードできなくなります。簡潔にするために、部分的な MIME ヘッダーのみを表示します。
Content-Transfer-Encoding: base64
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
OK、これを解析しても問題なく、まさに期待どおりの結果になります。そして、99% の場合、コードを使用してバッファー内の各文字が有効な Base64 文字であることを少なくとも検証することは、完全に機能します。しかし、次の例では、さらに問題が生じます。
Content-Transfer-Encoding: base64
http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu
これは Base64 エンコーディングのバージョンで、一部のメール リーダーが何としても MIME を解析したいという欲求を利用しようとするウイルスや他のもので見てきたもので、本またはむしろ RFC に厳密に従っているものではありません。よろしければ。
私の Base64 デコーダは、2 番目の例を次のデータ ストリームにデコードします。ここで、元のストリームはすべて ASCII データであることに注意してください。
[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8
両方の問題を一度に解決する良い方法を持っている人はいますか?異なるルールを適用してデータに 2 つの変換を実行し、結果を比較する以外に、それが可能であるかどうかさえわかりません。しかし、そのアプローチを取った場合、どの出力を信頼しますか?ASCII ヒューリスティックとは、 最高 解決策ですが、このコードが実際に関与するウイルス スキャナーのような複雑なものに、コード、実行時間、複雑さはどのくらい追加されるでしょうか?何が受け入れられる Base64 で何が受け入れられないかを学習するためにヒューリスティック エンジンをどのようにトレーニングしますか?
アップデート:
この質問の閲覧数が増え続けているため、私は C# アプリケーションで 3 年間、数十万のトランザクションで使用してきた単純な正規表現を投稿することにしました。正直に言うと、私は次の答えが好きです ガンボ 最高だったので、選択した回答として選択しました。しかし、C# を使用していて、少なくとも文字列または byte[] に有効な Base64 データが含まれているかどうかを検出する非常に簡単な方法を探している人にとっては、次の方法が非常にうまく機能することがわかりました。
[^-A-Za-z0-9+/=]|=[^=]|={3,}$
はい、これはただのことです 弦 Base64 データの形式であり、正しくフォーマットされていません RFC1341 メッセージ。したがって、このタイプのデータを扱う場合は、上記の正規表現を使用する前にそのことを考慮してください。他の目的 (URL、ファイル名、XML エンコーディングなど) で Base16、Base32、Radix、さらには Base64 を扱っている場合は、次のようになります。 非常に 読むことをお勧めします RFC4648 それ ガンボ この質問/回答セットの提案を使用する前に、実装で使用される文字セットとターミネータをよく理解しておく必要があるため、彼の回答で言及されています。
解決
から RFC 4648:
データの基本エンコードは、おそらく従来の理由により US-ASCII データに制限されている環境でデータを保存または転送するために、多くの状況で使用されます。
したがって、エンコードされたデータが危険であるかどうかは、そのデータの使用目的によって異なります。
ただし、Base64 でエンコードされた単語に一致する正規表現を探しているだけの場合は、次を使用できます。
^(?:[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})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{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 の単純な ASCII Base64 の例です。
これまでに見つけた最良の正規表現はここにあります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');
};