【问题标题】:How to check whether a string is Base64 encoded or not如何检查字符串是否是 Base64 编码的
【发布时间】:2012-01-24 04:24:23
【问题描述】:

我想解码一个 Base64 编码的字符串,然后将其存储在我的数据库中。如果输入不是 Base64 编码的,我需要抛出一个错误。

如何检查字符串是否经过 Base64 编码?

【问题讨论】:

  • 为什么?怎么会出现这种情况?
  • 不指定您所针对的编程语言(和/或)操作系统,这是一个非常开放的问题
  • 您所能确定的只是该字符串仅包含对 base64 编码字符串有效的字符。可能无法确定该字符串是某些数据的 base64 编码版本。例如test1234 是一个有效的base64 编码字符串,当你解码它时你会得到一些字节。没有任何独立于应用程序的方法可以得出结论 test1234 不是 base64 编码字符串。

标签: base64


【解决方案1】:

您可以使用以下正则表达式来检查字符串是否构成有效的 base64 编码:

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

在base64编码中,字符集是[A-Z, a-z, 0-9, and + /]。如果剩余长度小于 4,则用 '=' 字符填充字符串。

^([A-Za-z0-9+/]{4})* 表示字符串以 0 个或多个 base64 组开头。

([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$ 表示字符串以以下三种形式之一结尾:[A-Za-z0-9+/]{4}[A-Za-z0-9+/]{3}=[A-Za-z0-9+/]{2}==

【讨论】:

  • 只是想验证一下,所以请帮助解决我的问题:这个正则表达式将始终仅引用 base64 字符串的保证是什么?如果有任何字符串没有空格并且是4个字符的倍数,那么该字符串是否会被视为base64字符串????
  • 那么它是一个可以解码的有效base64字符串。您可以添加最小长度约束;例如,不是四人一组的零次或多次重复,而是需要(比方说)四个或更多。这也取决于您的问题;如果您的用户经常用长词和纯 ASCII(夏威夷语?)的语言输入单个词,那么与非 base64 输入通常包含空格、标点符号等相比,它更容易出错。
  • 这只能说明输入可能是 b64编码值,但不能说明输入是否实际上是b64编码值。换句话说,abcd 会匹配,但它不一定代表 的编码值,而只是一个普通的abcd 输入
  • 您的正则表达式不正确,因为它与空字符串不匹配,它是根据 RFC 4648 对零长度二进制数据进行 base64 编码。
  • @Adomas, "pass" 是一个完全有效的 base64 字符串,它解码为字节序列 0xa50xab0x2c。如果您没有更多的上下文来决定,为什么要先验丢弃它?
【解决方案2】:

如果你用的是Java,其实可以用commons-codec

import org.apache.commons.codec.binary.Base64;

String stringToBeChecked = "...";
boolean isBase64 = Base64.isArrayByteBase64(stringToBeChecked.getBytes());

[更新 1] 弃用通知 改为使用

Base64.isBase64(值);

   /**
     * Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
     * method treats whitespace as valid.
     *
     * @param arrayOctet
     *            byte array to test
     * @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
     *         {@code false}, otherwise
     * @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
     */
    @Deprecated
    public static boolean isArrayByteBase64(final byte[] arrayOctet) {
        return isBase64(arrayOctet);
    }

【讨论】:

  • 来自文档:isArrayByteBase64(byte[] arrayOctet) 已弃用。 1.5使用isBase64(byte[]),将在2.0中移除。
  • 您也可以使用 Base64.isBase64(String base64) 而不是自己将其转换为字节数组。
  • 遗憾的是,根据文档:commons.apache.org/proper/commons-codec/apidocs/org/apache/…:“测试给定的字符串以查看它是否仅包含 Base64 字母表中的有效字符。目前该方法将空格视为有效。”这意味着此方法有一些误报,例如“空白”或数字(“0”、“1”)。
  • 这个答案是错误的,因为给定 stringToBeChecked="some plain text" 然后它设置 boolean isBase64=true 即使它不是 Base64 编码的值。阅读 commons-codec-1.4 Base64.isArrayByteBase64() 的源代码,它只检查字符串中的每个字符是否有效以考虑进行 Base64 编码并允许空格。
  • @Ajay, politicalstudent 是一个有效的base64字符串,它解码成序列:a6 89 62 b6 27 1a 96 cb 6e 75 e9 ed
【解决方案3】:

你可以:

  • 检查长度是否为 4 个字符的倍数
  • 检查每个字符是否都在集合 A-Z、a-z、0-9、+、/ 中,除了末尾的填充,即 0、1 或 2 个“=”字符

如果您希望它是base64,那么您可能只需使用您平台上可用的任何库来尝试将其解码为字节数组,如果它不是有效的 base 64,则抛出异常。当然,这取决于您的平台。

【讨论】:

  • 解析与验证的不同之处至少在于它需要内存用于解码字节数组。因此,在某些情况下,这并不是最有效的方法。
  • @VictorYarema:我建议了仅验证方法(要点)和解析方法(在要点之后)。
【解决方案4】:

从 Java 8 开始,您可以简单地使用 java.util.Base64 来尝试解码字符串:

String someString = "...";
Base64.Decoder decoder = Base64.getDecoder();

try {
    decoder.decode(someString);
} catch(IllegalArgumentException iae) {
    // That string wasn't valid.
}

【讨论】:

  • 是的,这是一个选项,但不要忘记,catch 在 Java 中是非常昂贵的操作
  • 现在已经不是这样了。异常处理表现相当不错。您最好不要忘记 Java Regex 非常慢。我的意思是:真的很慢!实际上,解码 Base64 并检查它是否(不)工作而不是将字符串与上述正则表达式匹配,它实际上更快。我做了一个粗略的测试,Java 正则表达式匹配比在解码时捕获最终异常慢大约六倍(!!)。
  • 随着更多的测试运行,它实际上慢了 11 倍。是时候在 Java 中实现更好的正则表达式了。甚至使用 Java 中的 Nashorn JavaScript 引擎进行正则表达式检查也快得多。逆天。此外,JavaScript 正则表达式(使用 Nashorn)功能强大得多。
  • 使用 Java 11(而不是 Java 8),Regex 检查甚至慢了 22 倍。 ?(因为 Base64 解码变得更快了。)
  • 对字符串“Commit”使用这种方法将返回一个有效值,只是胡言乱语。所以这似乎不是万无一失的。
【解决方案5】:

在 PHP5 上试试这个

//where $json is some data that can be base64 encoded
$json=some_data;

//this will check whether data is base64 encoded or not
if (base64_decode($json, true) == true)
{          
   echo "base64 encoded";          
}
else 
{
   echo "not base64 encoded"; 
}

在 PHP7 中使用它

 //$string parameter can be base64 encoded or not

function is_base64_encoded($string){
 //this will check if $string is base64 encoded and return true, if it is.
 if (base64_decode($string, true) !== false){          
   return true;        
 }else{
   return false;
 }
}

【讨论】:

  • 这是什么语言?该问题是在没有提及语言的情况下提出的
  • 这行不通。阅读文档Returns FALSE if input contains character from outside the base64 alphabet.base64_decode
  • 怎么样?如果输入包含外部字符,那么它不是base64,对吧?
【解决方案6】:
var base64Rejex = /^(?:[A-Z0-9+\/]{4})*(?:[A-Z0-9+\/]{2}==|[A-Z0-9+\/]{3}=|[A-Z0-9+\/]{4})$/i;
var isBase64Valid = base64Rejex.test(base64Data); // base64Data is the base64 string

if (isBase64Valid) {
    // true if base64 formate
    console.log('It is base64');
} else {
    // false if not in base64 formate
    console.log('it is not in base64');
}

【讨论】:

    【解决方案7】:

    试试这个:

    public void checkForEncode(String string) {
        String pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(string);
        if (m.find()) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
    }
    

    【讨论】:

    • 谢谢,它成功了。实际上正在添加以下数据:image/jpeg;base64,删除它并且工作正常。
    【解决方案8】:

    无法检查字符串是否经过 base64 编码。只能验证该字符串是否为 base64 编码字符串格式,这意味着它可能是由 base64 编码生成的字符串(要检查该字符串是否可以针对正则表达式进行验证,或者可以使用库,很多这个问题的其他答案提供了很好的检查方法,所以我不会详细说明)。

    例如,字符串flow 是一个有效的base64 编码字符串。但是无法知道它只是一个简单的字符串,一个英文单词flow,还是base 64编码的字符串~Z0

    【讨论】:

      【解决方案9】:

      检查 IF 字符串的长度是 4 的倍数。之后使用此正则表达式确保字符串中的所有字符都是 base64 字符。

      \A[a-zA-Z\d\/+]+={,2}\z

      如果您使用的库添加换行符以遵守每行最多 76 个字符的规则,请将它们替换为空字符串。

      【讨论】:

      【解决方案10】:

      有很多variants of Base64,因此请考虑确定您的字符串是否类似于您希望处理的变体。因此,您可能需要针对索引和填充字符(即+/=)调整下面的正则表达式。

      class String
        def resembles_base64?
          self.length % 4 == 0 && self =~ /^[A-Za-z0-9+\/=]+\Z/
        end
      end
      

      用法:

      raise 'the string does not resemble Base64' unless my_string.resembles_base64?
      

      【讨论】:

        【解决方案11】:
        /^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/
        

        这个正则表达式帮助我在rails中的应用程序中识别base64,我只有一个问题,它识别字符串“errorDescriptcion”,我生成一个错误,解决它只需验证一个字符串的长度。

        【讨论】:

        • 上面的正则表达式 /^.....$/.match(my_string) 通过说“不匹配的关闭”来给出格式错误
        • 并带有'char-class的过早结束:/^(([A-Za-z0-9+/'语法错误。
        • 没关系通过在每个 / 字符前添加 \ 来修复它。
        • errorDescription 是一个有效的 base64 字符串,它解码为二进制字节序列(十六进制):7a ba e8 ac 37 ac 72 b8 a9 b6 2a 27
        • 它非常适合我检查 base64 编码的字符串。
        【解决方案12】:

        这适用于 Python:

        import base64
        
        def IsBase64(str):
            try:
                base64.b64decode(str)
                return True
            except Exception as e:
                return False
        
        if IsBase64("ABC"):
            print("ABC is Base64-encoded and its result after decoding is: " + str(base64.b64decode("ABC")).replace("b'", "").replace("'", ""))
        else:
            print("ABC is NOT Base64-encoded.")
        
        if IsBase64("QUJD"):
            print("QUJD is Base64-encoded and its result after decoding is: " + str(base64.b64decode("QUJD")).replace("b'", "").replace("'", ""))
        else:
            print("QUJD is NOT Base64-encoded.")
        

        总结: IsBase64("string here") 返回 true 如果 string here 是 Base64 编码的,它返回 false 如果 string here 不是 Base64 编码的。

        【讨论】:

          【解决方案13】:

          C# 这表现很棒:

          static readonly Regex _base64RegexPattern = new Regex(BASE64_REGEX_STRING, RegexOptions.Compiled);
          
          private const String BASE64_REGEX_STRING = @"^[a-zA-Z0-9\+/]*={0,3}$";
          
          private static bool IsBase64(this String base64String)
          {
              var rs = (!string.IsNullOrEmpty(base64String) && !string.IsNullOrWhiteSpace(base64String) && base64String.Length != 0 && base64String.Length % 4 == 0 && !base64String.Contains(" ") && !base64String.Contains("\t") && !base64String.Contains("\r") && !base64String.Contains("\n")) && (base64String.Length % 4 == 0 && _base64RegexPattern.Match(base64String, 0).Success);
              return rs;
          }
          

          【讨论】:

          • Console.WriteLine("test".IsBase64()); // true
          • 建议切换编程语言来解决问题通常是无效的响应。
          【解决方案14】:

          没有办法区分字符串和base64编码,除非你的系统中的字符串有一些特定的限制或标识。

          【讨论】:

            【解决方案15】:

            当您知道原始内容的长度(例如校验和)时,此 sn-p 可能很有用。它检查编码形式的长度是否正确。

            public static boolean isValidBase64( final int initialLength, final String string ) {
              final int padding ;
              final String regexEnd ;
              switch( ( initialLength ) % 3 ) {
                case 1 :
                  padding = 2 ;
                  regexEnd = "==" ;
                  break ;
                case 2 :
                  padding = 1 ;
                  regexEnd = "=" ;
                  break ;
                default :
                  padding = 0 ;
                  regexEnd = "" ;
              }
              final int encodedLength = ( ( ( initialLength / 3 ) + ( padding > 0 ? 1 : 0 ) ) * 4 ) ;
              final String regex = "[a-zA-Z0-9/\\+]{" + ( encodedLength - padding ) + "}" + regexEnd ;
              return Pattern.compile( regex ).matcher( string ).matches() ;
            }
            

            【讨论】:

              【解决方案16】:

              如果 RegEx 不起作用并且您知道原始字符串的格式样式,则可以通过对该格式进行正则表达式来反转逻辑。

              例如,我使用 base64 编码的 xml 文件,只检查文件是否包含有效的 xml 标记。如果不是,我可以假设它是 base64 解码的。这不是很动态,但适用于我的小型应用程序。

              【讨论】:

                【解决方案17】:

                这适用于 Python:

                def is_base64(string):
                    if len(string) % 4 == 0 and re.test('^[A-Za-z0-9+\/=]+\Z', string):
                        return(True)
                    else:
                        return(False)
                

                【讨论】:

                  【解决方案18】:

                  使用前面提到的正则表达式试试这个:

                  String regex = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
                  if("TXkgdGVzdCBzdHJpbmc/".matches(regex)){
                      System.out.println("it's a Base64");
                  }
                  

                  ...我们也可以做一个简单的验证,比如如果有空格就不能是Base64:

                  String myString = "Hello World";
                   if(myString.contains(" ")){
                     System.out.println("Not B64");
                   }else{
                      System.out.println("Could be B64 encoded, since it has no spaces");
                   }
                  

                  【讨论】:

                  • 好的,那你能给个解决办法吗?
                  【解决方案19】:

                  如果在解码时我们得到一个带有 ASCII 字符的字符串,那么这个字符串是 未编码

                  (RoR)红宝石解决方案:

                  def encoded?(str)
                    Base64.decode64(str.downcase).scan(/[^[:ascii:]]/).count.zero?
                  end
                  
                  def decoded?(str)
                    Base64.decode64(str.downcase).scan(/[^[:ascii:]]/).count > 0
                  end
                  

                  【讨论】:

                    【解决方案20】:
                    Function Check_If_Base64(ByVal msgFile As String) As Boolean
                    Dim I As Long
                    Dim Buffer As String
                    Dim Car As String
                    
                    Check_If_Base64 = True
                    
                    Buffer = Leggi_File(msgFile)
                    Buffer = Replace(Buffer, vbCrLf, "")
                    For I = 1 To Len(Buffer)
                        Car = Mid(Buffer, I, 1)
                        If (Car < "A" Or Car > "Z") _
                        And (Car < "a" Or Car > "z") _
                        And (Car < "0" Or Car > "9") _
                        And (Car <> "+" And Car <> "/" And Car <> "=") Then
                            Check_If_Base64 = False
                            Exit For
                        End If
                    Next I
                    End Function
                    Function Leggi_File(PathAndFileName As String) As String
                    Dim FF As Integer
                    FF = FreeFile()
                    Open PathAndFileName For Binary As #FF
                    Leggi_File = Input(LOF(FF), #FF)
                    Close #FF
                    End Function
                    

                    【讨论】:

                      【解决方案21】:

                      对于 Flutter,我测试了上面的几个 cmets 并将其转换为 dart 函数,如下所示

                        static bool isBase64(dynamic value) {
                      
                          if (value.runtimeType == String){
                            
                            final RegExp rx = RegExp(r'^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$',
                                multiLine: true,
                                unicode: true,
                            );
                      
                            final bool isBase64Valid = rx.hasMatch(value);
                      
                            if (isBase64Valid == true) {return true;}
                            else {return false;}
                      
                          }
                      
                          else {return false;}
                      
                        }
                      

                      【讨论】:

                        【解决方案22】:
                        import java.util.Base64;
                        
                            public static String encodeBase64(String s) {
                                return Base64.getEncoder().encodeToString(s.getBytes());
                            }
                        
                            public static String decodeBase64(String s) {
                                try {
                                    if (isBase64(s)) {
                                        return new String(Base64.getDecoder().decode(s));
                                    } else {
                                        return s;
                                    }
                                } catch (Exception e) {
                                    return s;
                                }
                            }
                        
                            public static boolean isBase64(String s) {
                                String pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$";
                                Pattern r = Pattern.compile(pattern);
                                Matcher m = r.matcher(s);
                        
                                return m.find();
                            }
                        

                        【讨论】:

                          【解决方案23】:

                          我尝试使用这个,是的,它正在工作

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

                          但我添加了条件来检查至少字符的结尾是=

                          string.lastIndexOf("=") >= 0
                          

                          【讨论】:

                          • 为什么检查=:您使用的是什么规格的Base64end of the character 是什么意思,非负数 lastIndexOf() 如何检查?
                          • 大部分我的base64 字符的返回总是在末尾有=
                          • 并非所有 base 64 编码字符串都以 = 结尾,例如:rYNltxhaxFAdr3ex8JFFtyCWHNRLCKyPyYei3xo05yHJEXmh3GZQxWm0NSP3tWBkMoIqrHQibfQmYpw-i6TspDJ0M3A1Z1FRWU1wM3V3aGZ1eTViOGJk
                          猜你喜欢
                          • 1970-01-01
                          • 2012-09-01
                          • 1970-01-01
                          • 2016-12-17
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多