使用uri_escape_utf8后无法解码字符串的Perl技术问题
解决方案
核心问题出在加密后的二进制数据被当成UTF-8字符串处理了。
加密函数encrypter返回的是Blowfish加密后的二进制字节流,不是合法的UTF-8字符串。当你用uri_escape_utf8处理它时,Perl会把这个二进制数据当作UTF-8编码的字符串来转义,但二进制数据大概率包含无效的UTF-8序列,转义后再通过Encode::decode('utf8', ...)还原时,会因为无效序列导致数据损坏,最终解密失败返回空值。而uri_escape是直接对字节进行转义,不会假设数据是UTF-8,所以能正常工作。
要解决这个问题,你需要:
- 加密后先把二进制数据转换成安全的文本格式(比如Base64),再用
uri_escape_utf8处理; - 解密前先反转义,再解码Base64得到原始二进制密文,最后解密。
修改后的加密端代码
use MIME::Base64; # 加密后转Base64(第二个参数为空字符串避免换行),再执行uri_escape_utf8 $encodedUsername = uri_escape_utf8(encode_base64(encrypter($u), ''));
修改后的解密端代码
use MIME::Base64; # 先反转义URL编码,再解码Base64得到二进制密文,最后解密 $enc = decode_base64(uri_unescape($encodedUsername)); $final = unencrypter($enc);
为什么这样可行?因为Base64会把任意二进制数据转换成仅包含ASCII字符的字符串,这样uri_escape_utf8处理时不会出现UTF-8无效序列的问题,JavaScript的encodeURIComponent处理Base64字符串也完全兼容,传输后能完整还原原始密文。
另外补充:你的加密函数里用pack('A8', $val)会用空格填充不足8位的字符串,解密后用unpack('A8', $val)会截断末尾空格,这个逻辑没问题,但如果原始字符串本身末尾有空格,会被截断,若不符合需求可以调整填充方式(比如用pack('a8', $val)用null字节填充)。
内容的提问来源于stack exchange,提问作者Jon Schlossberg
相关产品推荐
相关产品推荐

