为何同一PHP加密函数对相同字符串生成不同加密结果?
问题描述
我使用如下PHP加密函数处理字符串:
function encrypt_decrypt($action, $string) { $output = false; $encrypt_method = 'AES-256-ECB'; $secret_key = 'gT4ThOvcaFDccFFV21mg5hPzglZsY73T'; $key = hash('sha256', $secret_key); if ( $action == 'encrypt' ) { $output = openssl_encrypt($string, $encrypt_method, $key, 0); $output = base64_encode($output); } else if( $action == 'decrypt' ) { $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0); } return $output; }
该函数在两个未修改的PHP文件中调用,仅存在以下差异:
File1.php 通过HTTP GET请求获取字符串:
$Email = htmlspecialchars($_GET["Email"]); $ENC_Email = encrypt_decrypt("encrypt",$Email); echo($ENC_Email);
File2.php 从Cookie中获取字符串:
$Email = $_COOKIE['Email']; $enc = encrypt_decrypt("encrypt",$Email); echo($enc);
两个文件输出的$Email变量内容看似一致,但最终生成的加密字符串却不相同,请问忽略了什么问题?
问题原因与解决办法
加密结果不一致的核心是两个文件传入加密函数的字符串,看似内容相同,但实际二进制字节序列存在差异,具体可能情况如下:
1. htmlspecialchars的编码差异
File1用htmlspecialchars处理GET参数,File2直接读取Cookie值。htmlspecialchars的默认编码在PHP 5.6及以上是UTF-8,5.6以下为ISO-8859-1。如果运行环境编码不一致,或原始字符串包含非ASCII字符(比如带重音的邮箱地址),htmlspecialchars处理后的字符串字节序列会和Cookie中的原始字符串不同,加密算法对字节序列敏感,自然输出不同密文。
2. 不可见字符的差异
Cookie中的值可能包含不可见空白字符(比如末尾换行符、空格、制表符),这些字符肉眼无法分辨,但会被加密函数当作有效内容处理;而GET参数通常不会携带这类字符,或被浏览器自动截断,导致两个字符串实际内容不同。
3. URL编码的隐形处理
浏览器存储Cookie时,会自动对特殊字符(比如&、=、空格等)做URL编码,PHP的$_COOKIE会自动解码这些字符;但File1中htmlspecialchars会把&转成&,此时即使显示内容一致,实际字符串已被修改,加密结果自然不同。
快速验证方法
在两个文件中分别添加以下代码,对比输出结果:
// File1.php echo bin2hex($Email) . "\n"; echo strlen($Email) . "\n"; // File2.php echo bin2hex($Email) . "\n"; echo strlen($Email) . "\n";
如果十六进制字符串或长度不一致,说明两个$Email的实际内容存在差异。
解决办法
- 统一字符串处理逻辑:要么两个文件都用
htmlspecialchars处理,要么都不处理,确保传入加密函数的字符串完全一致。 - 明确指定
htmlspecialchars的编码参数,避免环境差异:$Email = htmlspecialchars($_GET["Email"], ENT_QUOTES, 'UTF-8'); - 对Cookie值做清理处理,比如去除首尾空白:
$Email = trim($_COOKIE['Email']);
内容的提问来源于stack exchange,提问作者M_Arad
相关产品推荐
相关产品推荐

