RegEx解析或验证Base64数据


99

是否可以使用RegEx来验证或清除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,什么不是?


更新:

对于这个问题继续得到的观点,我决定发布一个简单的RegEx,该正则表达式已经在C#应用程序中使用了3年,涉及数十万笔交易。老实说,我最喜欢Gumbo给出的答案,这就是为什么我选择它作为选定答案。但是对于使用C#并寻找一种至少能检测出一个字符串或byte []是否包含有效Base64数据的快速方法的人,我发现以下内容对我来说非常有效。

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

是的,这仅适用于STRING的Base64数据,而不是格式正确的RFC1341消息。因此,如果您要处理此类数据,请在尝试使用上述RegEx之前将其考虑在内。如果您出于其他目的(URL,文件名,XML编码等)使用Base16,Base32,Radix或什至Base64,那么强烈建议您阅读Gumbo在其回答中提到的RFC4648,因为您需要保持良好状态在尝试使用此问题/答案集中的建议之前,请了解实现所使用的字符集和终止符。


我想您必须更好地定义任务。完全不清楚您的目标是:严格?解析100%的样本?...
ADEpt

您的第一个示例应为“ VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4 =”
jfs

为什么不使用您的语言使用标准解决方案?为什么需要基于正则表达式的手写解析器?
jfs

1
好问题。尽管我通过对NPM返回的以base64编码的SHA运行UPDATE regex进行了尝试,但它失败了,而选定答案中的regex 正常运行
乔什·哈布达斯

1
不确定UPDATE正则表达式如何在没有更正的情况下仍然发布,但是看起来作者打算^方括号放在外面,作为开始锚。然而,一个更好的正则表达式,而又不会像公认的答案那么复杂,将是^[-A-Za-z0-9+/]*={0,3}$
kael 19'Nov 19'22

Answers:


145

RFC 4648中

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

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

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

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

10
最简单的解决方案是在验证之前去除所有空格(根据RFC会被忽略)。
本·布兰克

2
填充的最后一个非捕获组是可选的。
Gumbo

4
起初,我对这种复杂性表示怀疑,但它的验证性很好。如果您只想匹配base64-ish,我会想出^ [a-zA-Z0-9 + /] = {0,3} $,这更好!
Lodewijk 2014年

3
@BogdanNechyporenko这是因为name(十六进制)字节序列是有效的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 syed

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
为什么空字符串无效?
Josh Lee

8
它不是。但是,如果您使用正则表达式来查找给定的字符串是否为base64,则您可能对空字符串不感兴趣。至少我知道我不是。
njzk2 2011年

4
@LayZee:如果这样做,则强制base64字符串至少包含4个大小的块,从而呈现有效值(例如MQ==与表达式不匹配)
njzk2,2013年

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示例的简单ASCII Base64。


我可以同意,但是URL中的所有其他字母都恰好是有效的base64 ...所以,您在哪里画线?只是在换行符?(我见过那些在行中间只有几个随机字符的人。不能因此而扔掉行的其余部分,恕我直言)……
LarryF

@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);
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.