120

是否可以使用正则表达式来验证或清理 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 编码版本,而不是那些严格按照书本,或者更确切地说是 RFC 的东西;如果你愿意的话。

我的 Base64 解码器将第二个示例解码为以下数据流。请记住,原始流都是 ASCII 数据!

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

任何人有一个很好的方法来一次解决这两个问题?我不确定这是否可能,除了对应用了不同规则的数据进行两次转换并比较结果之外。但是,如果您采用这种方法,您信任哪个输出?似乎 ASCII 启发式方法是最好的解决方案,但是对于像病毒扫描程序这样复杂的东西,这段代码实际上参与其中,会增加多少代码、执行时间和复杂性?您将如何训练启发式引擎以了解什么是可接受的 Base64,什么不是?


更新:

对于这个问题继续获得的视图数量,我决定发布我在 C# 应用程序中使用了 3 年的简单正则表达式,其中包含数十万个事务。老实说,我最喜欢Gumbo给出的答案,这就是我选择它作为选定答案的原因。但是对于任何使用 C# 并且正在寻找一种非常快速的方法来至少检测字符串或字节 [] 是否包含有效的 Base64 数据的人,我发现以下内容对我来说非常有效。

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

是的,这只是针对 Base64 数据的字符串,而不是格式正确的RFC1341消息。因此,如果您正在处理这种类型的数据,请在尝试使用上述 RegEx 之前考虑到这一点。如果您出于其他目的(URL、文件名、XML 编码等)处理 Base16、Base32、Radix 甚至 Base64,那么强烈建议您阅读Gumbo在他的回答中提到的RFC4648,因为您需要做好在尝试使用此问题/答案集中的建议之前,请了解实现使用的字符集和终止符。

4

8 回答 8

170

来自RFC 4648

数据的基本编码在许多情况下用于在可能由于遗留原因仅限于 US-ASCII 数据的环境中存储或传输数据。

因此,是否应将数据视为危险数据取决于编码数据的使用目的。

但是,如果您只是在寻找一个正则表达式来匹配 Base64 编码的单词,您可以使用以下内容:

^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
于 2009-01-24T00:40:53.653 回答
41
^(?:[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})$
于 2011-05-04T14:33:26.517 回答
6

到目前为止提供的答案未能检查 Base64 字符串是否将所有填充位设置为 0,因为它是 Base64 的规范表示(这在某些环境中很重要,请参阅https://www.rfc-editor。 org/rfc/rfc4648#section-3.5),因此,它们允许对同一二进制字符串使用不同编码的别名。这可能是某些应用程序中的安全问题。

这是验证给定字符串不仅是有效的 base64 字符串,而且是二进制数据的规范 base64 字符串的正则表达式:

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

引用的 RFC 认为空字符串是有效的(参见https://www.rfc-editor.org/rfc/rfc4648#section-10),因此上述正则表达式也是如此。

base64url 的等效正则表达式(再次参考上面的 RFC)是:

^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-][AQgw]==|[A-Za-z0-9_-]{2}[AEIMQUYcgkosw048]=)?$
于 2020-10-21T15:50:43.000 回答
5

" : " 和 " . " 都不会出现在有效的 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。

于 2009-01-24T01:01:49.850 回答
5

要验证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|svg\+xml)(?:;charset=utf-8)?;base64,(?:[A-Za-z0-9]|[+/])+={0,2}/;
    return base64Image && regex.test(base64Image);
  }
于 2020-05-06T07:46:51.357 回答
5

检查 RFC-4648 合规性强制规范编码的最短正则表达式(即所有填充位设置为 0):

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

实际上,这是这个那个答案的混合。

于 2021-08-27T18:32:26.663 回答
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');
};
于 2015-03-26T09:33:03.747 回答
4

这是一个替代的正则表达式:

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

它满足以下条件:

  • 字符串长度必须是四的倍数 -(?=^(.{4})*$)
  • 内容必须是字母数字字符或 + 或 / -[A-Za-z0-9+/]*
  • 它的末尾最多可以有两个填充 (=) 字符 -={0,2}
  • 它接受空字符串
于 2020-09-05T21:44:29.137 回答