如何检查一个字符串是否为Base64编码

282

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

如何检查一个字符串是否为Base64编码?


1
为什么?这种情况怎么会出现? - user207421
3
这是一个非常开放的问题,没有指定你要针对哪种编程语言和/或操作系统。 - bcarroll
12
你所能确定的是该字符串仅包含在Base64编码字符串中有效的字符。但可能无法确定该字符串是否为某些数据的Base64编码版本。例如,test1234是一个有效的Base64编码字符串,解码后会得到一些字节。没有应用程序独立的方法可以得出test1234不是Base64编码字符串的结论。 - Kinjal Dixit
https://play.golang.org/p/RnEBFCJ9h0 - BentCoder
25个回答

339
您可以使用以下正则表达式来检查一个字符串是否是有效的base64编码:
^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$

在Base64编码中,字符集为[A-Z, a-z, 0-9, + /]。如果剩余长度小于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}==


18
我来翻译您的问题:我想确认一下,这个正则表达式是否保证只匹配base64字符串?如果有一个没有空格且长度是4的倍数的字符串,它会被视为base64字符串吗? - DShah
5
那么,这是一个有效的Base64字符串,可以进行解码。您可以添加最小长度限制;例如,不再允许零个或多个四个一组的重复,而是要求至少为四个以上。这也取决于您的问题;如果您的用户经常输入长单词和纯ASCII(夏威夷语?),那么错误可能会更多,因为非Base64输入通常包含空格、标点等。 - tripleee
75
这只是说明输入可能是一个base64编码值,但并不意味着输入实际上就是一个base64编码值。换句话说,abcd会匹配,但并不一定代表编码了的结果,而只是一个普通的abcd输入。 - Tzury Bar Yochay
5
您的正则表达式有误,因为它不能匹配空字符串,而根据RFC 4648规定,空字符串是零长度二进制数据的Base64编码。请注意修改。 - reddish
8
@Adomas,“pass”是一个完全有效的base64字符串,解码后变成字节序列0xa5、0xab和0x2c。如果您没有更多的上下文来决定,为什么要事先将其丢弃呢? - Luis Colorado
显示剩余15条评论

72
如果您正在使用Java,实际上可以使用commons-codec库。
import org.apache.commons.codec.binary.Base64;

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

[更新 1] 废弃通知 请改用

Base64.isBase64(value);

   /**
     * 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);
    }

22
从文档中: isArrayByteBase64(byte[] arrayOctet) 已弃用。 1.5版本后请使用isBase64(byte[]),2.0版本将删除。 - Avinash R
8
您可以使用Base64.isBase64(String base64)方法,而不是自己将其转换为字节数组。 - Saša
5
遗憾的是,根据文档:http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html#isBase64%28java.lang.String%29 : "测试给定的字符串是否仅包含 Base64 字母表中的有效字符。目前该方法将空格视为有效字符。" 这意味着这个方法可能会存在一些误判,例如空格或数字("0", "1")。 - Christian Vielma
9
这个答案是错误的,因为当给定stringToBeChecked="some plain text"时,它设置了 boolean isBase64=true,即使这不是一个Base64编码的值。请阅读commons-codec-1.4的源码Base64.isArrayByteBase64(),它仅检查字符串中的每个字符是否有效以被视为Base64编码,并允许空格。 - Brad
1
问题在于 isBase64("a") 返回 true。这是一个错误的测试,它只是确保所有字符都在 [A-Za-z0-9+/=] 中。 - Shloim
显示剩余3条评论

58

你可以这样做:

  • 检查长度是否是4个字符的倍数
  • 检查每个字符是否在A-Z、a-z、0-9、+、/等字符集中,除了末尾的填充字符,它可能是0、1或2个'='字符

如果你期望它是base64编码,那么你可以尝试使用你所在平台上可用的库将其解码为一个字节数组,如果不是有效的base 64,则抛出异常。当然,这取决于你所在的平台。


解析与验证至少在需要为解码的字节数组分配内存这一事实上存在差异。因此,在某些情况下,这不是最有效的方法。 - Victor Yarema
3
@VictorYarema:我建议采用两种方法,一种是仅验证的方法(项目符号),另一种是解析方法(在项目符号之后)。 - Jon Skeet
1
当您尝试在原始电子邮件中检测base64编码时,这将变得非常有趣。 MIME标头偶尔是引用可打印字符、非ASCII字符、非UTF8字符和某种程度的base64的奇怪混合。例如:=?windows-874?B?M0JCIGUtQmlsbCCgIEEvQyBOby4gNDEwMDQ1Nzg3IOC01825IDAzLzIwMjIgSU5WOjM2NTAzMjYwMzAwNjky?=;现成的电子邮件客户端可以毫不费力地处理所有这些,但这真的很混乱。 - ocodo

37

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

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

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

4
是的,这是一个选项,但不要忘记在Java中捕获异常是非常昂贵的操作。 - panser
14
不再是这样了。异常处理表现得非常好。你最好不要忘记Java正则表达式非常慢。我的意思是:真的很慢!实际上,解码Base64并检查它是否(不)起作用比使用上述正则表达式匹配字符串更快。 我进行了一个简单的测试,Java正则表达式匹配大约比捕获解码中可能出现的异常要慢六倍(!!)。 - Sven Döring
8
使用Java 11(而不是Java 8)进行正则表达式检查,速度甚至慢了22倍。(因为Base64解码更快了。) - Sven Döring
3
使用这种方法处理字符串 "Commit" 会返回一个有效但无意义的值,因此似乎并不是绝对可靠的。 - Alain P
2
@seunggabi 为什么在字符串“dev”上会抛出异常? - Philippe
显示剩余5条评论

15
尝试这样做,适用于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.
    return base64_decode($string, true) !== false;
}

2
这是什么语言?这个问题没有指定具体的编程语言。 - Ozkan
这个不会起作用。阅读文档 如果输入中包含来自base64字母表之外的字符,则返回FALSE。 base64_decode - Aley
2
如果输入包含外部字符,那么它就不是Base64,对吗? - Suneel Kumar

9
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
无法检查字符串是否已经进行了base64编码。只能验证该字符串是否符合base64编码的格式,这意味着它可能是由base64编码产生的字符串(可以通过正则表达式或库来验证该字符串,许多其他答案提供了良好的检查方法,因此我不会详细介绍)。
例如,字符串“flow”是一个有效的base64编码字符串。但是无法确定它只是一个简单的字符串、一个英文单词“flow”,还是base64编码的字符串“~Z0”。

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");
    }
}

谢谢,它完成了工作。实际上,我得到了以下内容的前缀 data:image/jpeg;base64, 将其删除后就可以正常工作了。 - Vasantha Kumar Boddu

5

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

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

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


提到的链接显示404错误。请检查并更新。 - Ankur
抱歉 @AnkurKumar,但这就是当人们拥有不酷的URL时发生的事情:它们会一直变化。我不知道它现在移动到哪里了。我希望你能通过谷歌找到其他有用的资源。 - Yaw Boakye
你可以随时从web.archive.org获取旧页面-这是原始网址。http://web.archive.org/web/20120919035911/http://www.ict.griffith.edu.au/anthony/info/crypto/base64.hints 或者我在这里发布了文本:https://gist.github.com/mika76/d09e2b65159e435e7a4cc5b0299c3e84 - Mladen Mihajlovic

5

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?

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