我注意到每当我对一个字符串进行base64编码时,末尾会添加一个"="字符。我可以删除这个字符,然后在解码之前将其添加回去吗?这样做是否存在风险?换句话说,这个"="字符是否总是被添加,还是只在某些情况下添加?
我希望我的编码字符串尽可能地短,因此想知道是否总是可以删除"="字符,然后在解码之前再添加回去。
我注意到每当我对一个字符串进行base64编码时,末尾会添加一个"="字符。我可以删除这个字符,然后在解码之前将其添加回去吗?这样做是否存在风险?换句话说,这个"="字符是否总是被添加,还是只在某些情况下添加?
我希望我的编码字符串尽可能地短,因此想知道是否总是可以删除"="字符,然后在解码之前再添加回去。
=
是填充字符。<!------------>
根据维基百科,Base64编码会额外添加一个填充字符,可用于将编码结果强制转换为由4个字符组成的整数倍(即在未编码的原二进制文本长度不是3的倍数时);在解码时需要丢弃这些填充字符,但可计算出未编码的文本的有效长度。通常最后一个非填充字符被编码为表示其代表的6位块将在其最低有效位上补齐0,最多可以在编码流的结尾处出现两个填充字符。
如果您控制另一端,在传输时可以将其删除,然后在解码之前通过检查字符串长度重新插入它。请注意,在传输过程中,数据将无法作为有效的Base64进行传输。
另外,另一位用户指出(适用于PHP用户):
请注意,在PHP中,base64_decode将接受没有填充的字符串,因此,如果您删除了填充以便稍后在PHP中处理,则无需将其添加回来。- Mahn Oct 16'14 at 16:33
因此,如果目标是PHP,您可以安全地删除填充并进行解码,而无需进行复杂的计算。=
字符直到成为4的倍数。在.NET中,可以使用以下代码实现:if (str.Length % 4 != 0) str += new string('=', 4 - str.Length % 4)
。 - SLaksbase64_decode
函数会接受没有填充字符的字符串,因此如果您在PHP中移除了填充字符以便稍后处理,就不需要再添加回来。 - MahnBase64.decode64
方法也是一样的;它可以在没有填充的情况下正常工作。我认为.NET的Convert.FromBase64String
方法是其中相对较严格的之一,实际上需要填充。 - Per Lundberg在 JavaScript 中,你可以像这样做:
// if this is your Base64 encoded string
var str = 'VGhpcyBpcyBhbiBhd2Vzb21lIHNjcmlwdA==';
// make URL friendly:
str = str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
// reverse to original encoding
if (str.length % 4 != 0){
str += ('===').slice(0, 4 - (str.length % 4));
}
str = str.replace(/-/g, '+').replace(/_/g, '/');
请参考这个 Fiddle:http://jsfiddle.net/7bjaT/66/
我曾经参与编写 Apache 的 commons-codec-1.4.jar Base64 解码器。在那段逻辑中,我们无需填充字符即可正常解码。文件结尾和流结尾本身就足以表明 Base64 消息已完成,不需要任何数量的 '=' 字符来标记!
我们在 commons-codec-1.4 中引入了 URL-Safe 变体,有意省略了填充字符以使数据更小。
或许更安全的回答是 "取决于你的解码器实现",但从逻辑上说,不需要填充符号也能写出一个解码器。
=
用于填充。base64字符串的长度应该是4的倍数,因此需要根据需要添加1或2个=
。
阅读:不,您不应该将其删除。
String CHARSET_NAME ="UTF-8";
编码
String base64 = new String(
Base64.encode(byteArray, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP),
CHARSET_NAME);
return base64.trim();
解码
byte[] bytes = Base64.decode(base64String,
Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_CLOSE | Base64.NO_WRAP);
在Java中,这等同于:
编码
private static String base64UrlEncode(byte[] input)
{
Base64 encoder = new Base64(true);
byte[] encodedBytes = encoder.encode(input);
return StringUtils.newStringUtf8(encodedBytes).trim();
}
解码
private static byte[] base64UrlDecode(String input) {
byte[] originalValue = StringUtils.getBytesUtf8(input);
Base64 decoder = new Base64(true);
return decoder.decode(originalValue);
}
我从未遇到过尾随“=”的问题,而且我也在使用Bouncycastle。
<?php
$str = 'base64 encoded string without equal signs stripped';
$str = str_pad($str, strlen($str) + (4 - ((strlen($str) % 4) ?: 4)), '=');
echo $str, "\n";
$str = str_pad($str, ceil(strlen($str)/4)*4, '=');
(结果相同) - Alexandre T.使用Python,您可以这样删除和添加base64填充:
from math import ceil
stripped = original.rstrip('=')
original = stripped.ljust(ceil(len(stripped) / 4) * 4, '=')
private static String getBase64StringWithoutPadding(String data) {
if(data == null) {
return "";
}
Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
return encoder.encodeToString(data.getBytes());
}
是的,有一些合法的情况下可以省略Base 64编码中的填充。
JSON Web Signature (JWS)标准 (RFC 7515) 要求 Base 64编码的数据省略填充。它期望:
使用所有结尾的 '=' 字符被省略的Base64编码(按照3.2节的规定),不包括任何换行符、空格或其他附加字符。请注意,空字节序列的base64url编码为空字符串。 (有关实现不带填充的base64url编码的说明,请参见附录C。)
JSON Web Token (JWT)标准 (RFC 7519)同样适用于此。
此外,Julius Musseau 的答案 表明 Apache's Base 64解码器不需要在 Base 64 编码数据中存在填充。