RegEx для анализа или проверки данных Base64

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

У меня есть декодер Base64, который не может полностью полагаться на входные данные, чтобы следовать спецификациям RFC. Таким образом, проблемы, с которыми я сталкиваюсь, - это такие проблемы, как, возможно, данные Base64, которые не могут быть разбиты на 78 (я думаю, что это 78, мне пришлось бы дважды проверить RFC, так что не делайте меня, если точное число неверно) строк или что линии не могут заканчиваться в CRLF; в том, что он может иметь только CR, или LF, или, возможно, ни один.

Итак, у меня было время анализировать данные Base64, отформатированные как таковые. В связи с этим примеры, подобные следующим, становятся невозможными для надежного декодирования. Для краткости я покажу только частичные заголовки MIME.

Content-Transfer-Encoding: base64

VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

Хорошо, поэтому синтаксический анализ это не проблема, и именно результат мы ожидаем. И в 99% случаев, используя любой код, чтобы хотя бы проверить, что каждый char в буфере является допустимым base64 char, отлично работает. Но следующий пример бросает ключ в микс.

Content-Transfer-Encoding: base64

http://www.stackoverflow.com
VGhpcyBpcyBzaW1wbGUgQVNDSUkgQmFzZTY0IGZvciBTdGFja092ZXJmbG93IGV4YW1wbGUu

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

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

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

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


UPDATE:

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

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

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

Ответ 1

Из RFC 4648:

Базовое кодирование данных используется во многих ситуациях для хранения или передачи данных в средах, которые, возможно, по наследству, ограничены данными US-ASCII.

Таким образом, это зависит от цели использования закодированных данных, если данные следует считать опасными.

Но если вы просто ищете регулярное выражение в соответствии с закодированными словами Base64, вы можете использовать следующее:

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

Ответ 2

^(?:[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})$

Ответ 3

Ни один из ":" или "." не появится в действительном 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 для exeaplele StackOverflow.

Ответ 4

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