Регулярное выражение для анализа или проверки данных Base64

можно ли использовать регулярное выражение для проверки или очистки данных Base64? Это простой вопрос, но факторы, которые управляют этим вопросом, делают его трудным.

у меня есть декодер Base64, который не может полностью полагаться на входные данные, чтобы следовать спецификациям RFC. Итак, проблемы, с которыми я сталкиваюсь, - это проблемы, такие как, возможно, данные 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

это версия кодировки Base64, которую я видел в некоторых вирусах и других вещах, которые пытаются воспользоваться некоторыми читателями почты, которые хотят проанализировать mime любой ценой, по сравнению с теми, которые идут строго по книге или, скорее, RFC; если хотите.

Мой декодер Base64 декодирует второй пример в следующий поток данных. И имейте в виду, что исходный поток-это все данные ASCII!

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

у кого-нибудь есть хороший способ решить обе проблемы сразу? Я даже не уверен, что это возможно, за исключением двух преобразований данных с различными правилами и сравнения результатов. Однако, если вы приняли этот подход, какой выход Вы доверяете? Похоже, что эвристика ASCII-это лучшие решение, но насколько больше кода, времени выполнения и сложности это добавит к чему-то так же сложно, как вирусный сканер, в котором этот код фактически участвует? Как бы вы обучили эвристический движок, чтобы узнать, что является приемлемым Base64, а что нет?


обновление:

до количества просмотров этот вопрос продолжает получать, я решил опубликовать простое регулярное выражение, которое я использую в приложении C# в течение 3 лет, с сотнями тысяч транзакций. Честно говоря, мне нравится ответ, данный Гамбо лучший, поэтому я выбрал его в качестве выбранного ответа. Но для тех, кто использует C# и ищет очень быстрый способ, по крайней мере, определить, содержит ли строка или байт[] допустимые данные Base64 или нет, я нашел следующее, чтобы работать очень хорошо для меня.

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

и да, это только для строка данных Base64, не отформатированных должным образом RFC1341 сообщение. Итак, если вы имеете дело с данными этого типа, Пожалуйста, возьмите это учтите, прежде чем пытаться использовать вышеуказанное регулярное выражение. Если Вы имеете дело с Base16, Base32, Radix или даже Base64 для других целей (URL-адреса, имена файлов, кодировка XML и т. д.), то это очень рекомендуем Вам прочитать RFC4648 это Гамбо упоминается в его ответе, поскольку вам нужно хорошо знать кодировку и Терминаторы, используемые реализацией, прежде чем пытаться использовать предложения в этом наборе вопросов/ответов.

4 ответов


С 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);

может быть то, что вы хотите. Он производит

это простой ASCII Base64 для StackOverflow exmaple.


лучший regexp, который я мог бы найти до сих пор здесь 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');
};