【问题标题】:RegEx to parse or validate Base64 dataRegEx 解析或验证 Base64 数据
【发布时间】:2010-10-03 06:28:05
【问题描述】:

是否可以使用正则表达式来验证或清理 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

这是我在一些病毒和其他东西中看到的 Base64 编码版本,它们试图利用一些邮件阅读者不惜一切代价想要解析 mime,而不是严格按照书本或 RFC 进行解析;如果你愿意的话。

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

[0x]86DB69FFFC30C2CB5A724A2F7AB7E5A307289951A1A5CC81A5CC81CDA5B5C1B19481054D0D
2524810985CD94D8D08199BDC8814DD1858DAD3DD995C999B1BDDC8195E1B585C1B194B8

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


更新:

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

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

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

【问题讨论】:

  • 我猜你必须更好地定义任务。完全不清楚您的目标是什么:严格?解析 100% 的样本? ...
  • 你的第一个例子应该是'VGhpcyBpcyBhIHNpbXBsZSBBU0NJSSBCYXNlNjQgZXhhbXBsZSBmb3IgU3RhY2tPdmVyZmxvdy4='
  • 为什么不使用您的语言的标准解决方案?为什么需要基于正则表达式的手写解析器?
  • 好问题。尽管我尝试了 UPDATE 正则表达式,方法是针对 NPM 和 it failed 返回的 base64 编码的 SHA 运行它,而所选答案中的正则表达式 works just fine
  • 不确定 UPDATE 正则表达式是如何在没有更正的情况下发布的,但看起来作者 打算^ 放在括号外,作为起始锚。然而,一个更好的正则表达式,而不像接受的答案那样复杂,将是^[-A-Za-z0-9+/]*={0,3}$

标签: regex base64 standards-compliance rfc


【解决方案1】:

来自RFC 4648

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

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

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

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

【讨论】:

  • 最简单的解决方案是在验证之前去掉所有空格(根据 RFC 将其忽略)。
  • 填充的最后一个非捕获组是可选的。
  • 起初我对复杂性持怀疑态度,但它验证得很好。如果您只想匹配 base64-ish,我会想出 ^[a-zA-Z0-9+/]={0,3}$,这样更好!
  • @BogdanNechyporenko 这是因为name 是(十六进制)字节序列9d a9 9e 的有效Base64 编码。
  • ^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$ 必须避免反弹
【解决方案2】:

:”和“.”都不会出现在有效的 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:除非对 base-64 编码数据进行完整性检查,否则您无法判断如何处理任何包含错误字符的 base-64 数据块。哪个是最好的启发式方法:忽略不正确的字符(允许任何和所有正确的字符)或拒绝行,还是拒绝批次?
  • (续):简短的回答是“这取决于” - 取决于数据的来源以及您在其中发现的各种混乱情况。
  • (已恢复):我从 cmets 看到您想接受任何可能是 base-64 的问题。因此,只需映射不在 base-64 字母表中的每个字符(请注意,有 URL 安全和其他此类变体编码),包括换行符和冒号,然后取剩下的。
【解决方案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,那么您可能对空字符串不感兴趣。至少我知道我不是。
  • @LayZee :如果你这样做,你会强制 base64 字符串包含至少一个 4 大小的块,从而使 MQ== 等有效值与你的表达式不匹配
  • @ruslan 也不应该。这不是一个有效的 base 64 字符串。 (大小为 23,而不是 // 4)。 AQENVg688MSGlEgdOJpjIUC= 是有效的形式。
  • @JinKwon base64 以 0、1 或 2 = 结尾。最后一个 ? 允许 0 =。将其替换为 {1} 需要 1 或 2 个结尾 =
【解决方案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');
};

【讨论】:

  • 没有\\n?可能会更好。
  • 这将在 JSON 字符串上失败
【解决方案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);
  }

【讨论】:

  • 谢谢!对于 base64 图像字符串开头的元属性非常有用。一个建议:(至少)缺少一个 mime 类型,svg+xml,因此第一个捕获组可能应该扩展到 (?:gif|png|jpeg|bmp|webp|svg\+xml)
  • @HynekS。是的。我更新了我的答案。谢谢:-)
【解决方案6】:

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

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

满足以下条件:

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

【讨论】:

    【解决方案7】:

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

    这是验证给定字符串不仅是有效的 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]=)?$
    

    【讨论】:

      【解决方案8】:

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

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

      其实这是thisthat 的混合答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-22
        • 1970-01-01
        • 2012-06-14
        相关资源
        最近更新 更多