如何检查一个有效的Base64编码字符串

176
在C#中,除了尝试转换并查看是否出现错误之外,还有其他方法可以判断一个字符串是否是Base 64编码的吗?我有类似这样的代码:
// Convert base64-encoded hash value into a byte array.
byte[] HashBytes = Convert.FromBase64String(Value);

我想要避免“无效字符在 Base-64 字符串中”的异常,如果值不是有效的 base 64 字符串。我只想要检查并返回 false,而不是处理异常,因为我预期有时候这个值不会是一个 base 64 字符串。有没有一种在使用 Convert.FromBase64String 函数之前进行检查的方法?


1
这取决于您想要多么“彻底”地进行检查。您可以像其他人提供的那样使用一些预验证,使用正则表达式,但这并不是唯一的指标。在某些情况下,base64编码需要使用“=”符号进行填充。如果填充不正确,即使输入与表达式匹配,也会出现错误。 - vcsjones
1
你的条件并不只是满足base64字符串。请考虑字符串\n\fLE16——你的方法会对此产生错误的判断结果。对于任何正在阅读并寻找一个无懈可击的方法的人来说,我建议捕获FormatException或使用适合规范的正则表达式,请参见https://dev59.com/unRB5IYBdhLWcg3w6LN2。 - nullable
4
我认为正则表达式应该是 @"^[a-zA-Z0-9\+/]*={0,2}$" - 4Z4T4R
1
这个解决方案不可靠。如果您添加了4个相同字符的字符串,它会失败。 - Bettimms
正则表达式将匹配几乎任何没有空格的字符串,因此无法用作“IsBase64String”测试。但是,如果您像@4Z4T4R建议的那样调整正则表达式,则可以将其用作IsValidBase64String。 - Dimitri Troncquo
显示剩余2条评论
20个回答

3
我会这样使用,这样我就不需要再次调用转换方法。
   public static bool IsBase64(this string base64String,out byte[] bytes)
    {
        bytes = null;
        // Credit: oybek http://stackoverflow.com/users/794764/oybek
        if (string.IsNullOrEmpty(base64String) || base64String.Length % 4 != 0
           || base64String.Contains(" ") || base64String.Contains("\t") || base64String.Contains("\r") || base64String.Contains("\n"))
            return false;

        try
        {
             bytes=Convert.FromBase64String(base64String);
            return true;
        }
        catch (Exception)
        {
            // Handle the exception
        }

        return false;
    }

2

Knibb High橄榄球队很棒!

这应该相对快速且准确,但我承认我没有经过全面测试,只是做了一些测试。

它避免了昂贵的异常、正则表达式,并且还避免了通过字符集进行循环,而是使用ASCII范围进行验证。

public static bool IsBase64String(string s)
    {
        s = s.Trim();
        int mod4 = s.Length % 4;
        if(mod4!=0){
            return false;
        }
        int i=0;
        bool checkPadding = false;
        int paddingCount = 1;//only applies when the first is encountered.
        for(i=0;i<s.Length;i++){
            char c = s[i];
            if (checkPadding)
            {
                if (c != '=')
                {
                    return false;
                }
                paddingCount++;
                if (paddingCount > 3)
                {
                    return false;
                }
                continue;
            }
            if(c>='A' && c<='z' || c>='0' && c<='9'){
                continue;
            }
            switch(c){ 
              case '+':
              case '/':
                 continue;
              case '=': 
                 checkPadding = true;
                 continue;
            }
            return false;
        }
        //if here
        //, length was correct
        //, there were no invalid characters
        //, padding was correct
        return true;
    }

1

所有答案都被整合到一个函数中,确保其结果100%准确。

1)使用以下函数:

string encoded = "WW91ckJhc2U2NHN0cmluZw==";
Console.WriteLine("Is string base64=" + IsBase64(encoded));

2) 以下是该函数:

public bool IsBase64(string base64String)
{
    try
    {
        if (!base64String.Equals(Convert.ToBase64String(Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(Convert.FromBase64String(base64String)))), StringComparison.InvariantCultureIgnoreCase) & !System.Text.RegularExpressions.Regex.IsMatch(base64String, @"^[a-zA-Z0-9\+/]*={0,2}$"))
        {
            return false;
        }
        else if ((base64String.Length % 4) != 0 || string.IsNullOrEmpty(base64String) || base64String.Length % 4 != 0 || base64String.Contains(" ") || base64String.Contains(Constants.vbTab) || base64String.Contains(Constants.vbCr) || base64String.Contains(Constants.vbLf))
        {
            return false;
        }
        else return true;
    }
    catch (FormatException ex)
    {
        return false;
    }
}

@管道 那时我还是个新手,请看现在。 - Sorry IwontTell
1
这样更好 ;) - Pipe

1

我想指出的是,迄今为止的所有答案都不太实用(取决于您的使用情况,但请耐心等待)。

它们中的所有答案都会对长度可被4整除且不包含空格的字符串返回错误的正面结果。 如果您调整缺少填充,则[aA-zZ0-9]+范围内的所有字符串都将注册为base64编码。

无论您检查有效字符和长度,还是使用异常或TryConvert方法,所有这些方法都会返回错误的正面结果

一些简单的例子:

  • "test"将注册为base64编码
  • "test1"如果您调整缺少填充(尾随'='),则将注册为base64编码
  • "test test"永远不会注册为base64编码
  • "tést"永远不会注册为base64编码

我并不是说这里描述的方法是无用的,但在生产环境中使用这些方法之前,您应该了解其限制


1
public static bool IsBase64String1(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return false;
            }
            try
            {
                Convert.FromBase64String(value);
                if (value.EndsWith("="))
                {
                    value = value.Trim();
                    int mod4 = value.Length % 4;
                    if (mod4 != 0)
                    {
                        return false;
                    }
                    return true;
                }
                else
                {

                    return false;
                }
            }
            catch (FormatException)
            {
                return false;
            }
        }

为什么你首先尝试转换,然后再控制其他事情。 - sonertbnc
@Snr 你说得对。我认为这就是他需要更改的内容: 如果 (value.EndsWith("=")) { value = value.Trim(); int mod4 = value.Length % 4; if (mod4 != 0) { return false; } Convert.FromBase64String(value); return true; } else { return false; } - Wajid khan

0
我建议创建一个正则表达式来完成此任务。 您必须检查类似于此的内容:[a-zA-Z0-9+/=] 您还必须检查字符串的长度。 对于这个问题我不太确定,但我相当确定如果某些内容被修剪(除了填充“=”),它会崩溃。
或者更好的办法是查看这个stackoverflow问题

0

没问题。只需确保每个字符都在a-zA-Z0-9/+之内,并且字符串以==结尾。(至少,这是最常见的Base64实现。你可能会发现一些实现使用不同于/+的字符作为最后两个字符。)


如果我理解正确,结尾字符取决于编码后文本的最终长度。因此,如果编码后文本长度不是4的倍数,则会包含'='。 - Rafael Diego Nicoletti

0

是的,由于Base64使用有限的一组字符将二进制数据编码为ASCII字符串,因此您可以使用以下正则表达式简单地进行检查:

/^[A-Za-z0-9\=\+\/\s\n]+$/s

这将确保字符串只包含A-Z、a-z、0-9、'+'、'/'、'='和空格。


那并不总是一种确定的方法。Base64使用末尾的=字符为您添加一些填充内容。如果该填充无效,则不是正确的Base64编码,即使它与您的正则表达式匹配。您可以通过找到一个以1或2个= 结尾的base64字符串,将其删除并尝试解码来演示此功能。 - vcsjones
我相信 OP 要求捕获非法字符,而不是判断字符串是否为合法的 Base64。如果是后者,你是正确的,但是使用异常来捕获 Base64 中的填充错误更容易。 - Rob Raisch
不是这样的,至少在 .Net 版本中,base64 解析器完全忽略填充。 - Jay

0
我刚碰到了一个非常类似的需求,在让用户使用 <canvas> 元素进行图像处理后,使用 .toDataURL() 获取结果图像并将其发送到后端。在保存图像之前,我想对其进行一些服务器验证,并使用其他答案中的代码实现了一个 ValidationAttribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class Bae64PngImageAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value == null || string.IsNullOrWhiteSpace(value as string))
            return true; // not concerned with whether or not this field is required
        var base64string = (value as string).Trim();

        // we are expecting a URL type string
        if (!base64string.StartsWith("data:image/png;base64,"))
            return false;

        base64string = base64string.Substring("data:image/png;base64,".Length);

        // match length and regular expression
        if (base64string.Length % 4 != 0 || !Regex.IsMatch(base64string, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None))
            return false;

        // finally, try to convert it to a byte array and catch exceptions
        try
        {
            byte[] converted = Convert.FromBase64String(base64string);
            return true;
        }
        catch(Exception)
        {
            return false;
        }
    }
}

正如您所看到的,我期望得到一个 image/png 类型的字符串,这是使用 .toDataURL()<canvas> 默认返回的类型。


0

检查Base64或普通字符串

public bool IsBase64Encoded(String str)
{

 try

  {
    // If no exception is caught, then it is possibly a base64 encoded string
    byte[] data = Convert.FromBase64String(str);
    // The part that checks if the string was properly padded to the
    // correct length was borrowed from d@anish's solution
    return (str.Replace(" ","").Length % 4 == 0);
  }
catch
  {
    // If exception is caught, then it is not a base64 encoded string
   return false;
  }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接