繁体   English   中英

使用 JavaScript 确定字符串是否在 base64 中

[英]Determine if string is in base64 using JavaScript

我正在使用window.atob('string') function 将字符串从 base64 解码为字符串。 现在我想知道,有什么方法可以检查“字符串”是否真的有效 base64? 如果字符串不是 base64,我希望收到通知,以便我可以执行不同的操作。

如果你想检查它是否可以解码,你可以简单地尝试解码它,看看它是否失败:

try {
    window.atob(str);
} catch(e) {
    // something failed

    // if you want to be specific and only catch the error which means
    // the base 64 was invalid, then check for 'e.code === 5'.
    // (because 'DOMException.INVALID_CHARACTER_ERR === 5')
}

基于@anders-marzi-tornblad 的答案,使用正则表达式对base64 有效性进行简单的真/假测试,如下所示:

var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;

base64regex.test("SomeStringObviouslyNotBase64Encoded...");             // FALSE
base64regex.test("U29tZVN0cmluZ09idmlvdXNseU5vdEJhc2U2NEVuY29kZWQ=");   // TRUE

2021 年更新

  • 根据下面的评论,这个基于正则表达式的解决方案提供了比简单地try `ing atob更准确的检查,因为后者不检查= -padding。 根据RFC4648 = -padding 只能在 base16 编码或隐含已知数据长度的情况下被忽略。
  • 正如kai暗示的,基于正则表达式的解决方案似乎也是最快的。 由于 jsperf 看起来很不稳定,我在 jsbench 上做了一个新的测试,证实了这一点。

这应该可以解决问题。

function isBase64(str) {
    if (str ==='' || str.trim() ===''){ return false; }
    try {
        return btoa(atob(str)) == str;
    } catch (err) {
        return false;
    }
}

如果“有效”意味着“其中只有 base64 字符”,则检查/[A-Za-z0-9+/=]/

如果“有效”表示“合法”base64 编码的字符串,那么您应该检查末尾的=

如果“有效”意味着解码后它是合理的,那么它需要领域知识。

我会为此使用正则表达式。 试试这个:

/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/

解释:

^                          # Start of input
([0-9a-zA-Z+/]{4})*        # Groups of 4 valid characters decode
                           # to 24 bits of data for each group
(                          # Either ending with:
    ([0-9a-zA-Z+/]{2}==)   # two valid characters followed by ==
    |                      # , or
    ([0-9a-zA-Z+/]{3}=)    # three valid characters followed by =
)?                         # , or nothing
$                          # End of input

此方法尝试解码然后编码并与原始文件进行比较。 也可以与引发解析错误的环境的其他答案结合使用。 从正则表达式的角度来看,它也可能有一个看起来像有效的 base64 但不是实际的 base64 的字符串。

if(btoa(atob(str))==str){
  //...
}

这是在我最喜欢的验证库之一中完成的:

const notBase64 = /[^A-Z0-9+\/=]/i;

export default function isBase64(str) {
  assertString(str); // remove this line and make sure you pass in a string
  const len = str.length;
  if (!len || len % 4 !== 0 || notBase64.test(str)) {
    return false;
  }
  const firstPaddingChar = str.indexOf('=');
  return firstPaddingChar === -1 ||
    firstPaddingChar === len - 1 ||
    (firstPaddingChar === len - 2 && str[len - 1] === '=');
}

https://github.com/chriso/validator.js/blob/master/src/lib/isBase64.js

由于这里发布的主要有两种可能性(regex vs try catch),我确实比较了两者的性能: https : //jsperf.com/base64-check/

正则表达式解决方案似乎更快更明显。 不确定正则表达式是否能捕获所有情况,但对于我的测试,它运行良好。

感谢@Philzen 的正则表达式!

ps

如果有人有兴趣找到安全解码 base64 字符串的最快方法(这就是我来到这里的方式): https : //jsperf.com/base64-decoding-check

对我来说,如果满足以下条件,字符串很可能是经过编码的 base64:

  1. 它的长度可以被 4 整除
  2. 使用AZ az 0-9 +/=
  3. 最后只使用= (0-2个字符)

所以代码是

function isBase64(str)
{
    return str.length % 4 == 0 && /^[A-Za-z0-9+/]+[=]{0,2}$/.test(str);
}

nodejs 中的实现(不仅验证允许的字符,还验证 base64 字符串)


    const validateBase64 = function(encoded1) {
        var decoded1 = Buffer.from(encoded1, 'base64').toString('utf8');
        var encoded2 = Buffer.from(decoded1, 'binary').toString('base64');
        return encoded1 == encoded2;
    }

我尝试了以下答案,但存在一些问题。

var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
base64regex.test(value)

当使用它时,“BBBBB”大写字母将是真实的。 “4444”也是如此。

我添加了一些代码来为我正常工作。

function (value) {
  var base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
  if (base64regex.test(value) && isNaN(value) && !/^[a-zA-Z]+$/.test(value)) {
  return decodeURIComponent(escape(window.atob(value)));
}

把我的结果扔在这里。 在我的例子中,有一个不是 base64 但有效的字符串 base64 所以它被解码成乱码。 (即根据通常的正则表达式,yyyyyyyy 有效 base64)

我的测试结果是首先检查字符串是否是有效的 base64 字符串,使用其他人在这里共享的正则表达式,然后解密它并测试它是否是有效的 ascii 字符串,因为(在我的情况下)我应该只取回 ascii 字符。 (这可能会扩展到包括可能不属于 ascii 范围的其他字符。)

这是多个答案的混合体。

let base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
function isBase64(str) {
    if (str ==='' || str.trim() ===''){ return false; }
    try {
        if (base64regex.test(str)) {
            return /^[\x00-\x7F]*$/.test(atob(str));
        } else {
            return false
        }
    } catch (err) {
        // catch
    }
}

与我的 JavaScript 答案一样,我不知道自己在做什么。 所以可能有更好的方法来写出来。 但它适用于我的需要,并涵盖了当您有一个不应为 base64 但有效且仍解密为 base64 的字符串时的情况。

我知道为时已晚,但我试图在这里让它变得简单;

function isBase64(encodedString) {
    var regexBase64 = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/;
    return regexBase64.test(encodedString);   // return TRUE if its base64 string.
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM