使用PHP OpenSSL验证RSA-SHA256签名失败问题排查
数字签名验证失败的解决方案
核心问题分析
前后端签名/验证流程存在两处关键不一致:
- 后端手动计算SHA256哈希并传入验证函数,但
openssl_verify会自动对原始数据执行哈希运算,且未指定SHA256算法(默认用SHA1) - 前后端生成的JSON字符串可能存在格式差异(如键顺序、转义规则),导致哈希源数据不一致
步骤1:修正后端验证逻辑
修改VerifyDigitalSignature函数
指定SHA256算法,让openssl_verify自动处理哈希:
public static function VerifyDigitalSignature($data, $base_64_digital_signature, $public_key){ // 明确指定SHA256算法,匹配前端签名逻辑 $isVerified = openssl_verify($data, base64_decode($base_64_digital_signature), $public_key, OPENSSL_ALGO_SHA256); return $isVerified; }
修改validateRsaLogin函数
移除手动哈希步骤,确保传入原始JSON字符串,同时统一JSON生成规则:
public function validateRsaLogin(Request $request){ // 对参数数组按键名排序,保证前后端JSON键顺序一致 $params = $request->post('Parameters'); ksort($params); // 统一JSON转义规则,避免斜杠、Unicode字符转义差异 $parameters = json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); // 直接传入原始JSON字符串进行验证,不再手动哈希 $signature = RsaKeys::VerifyDigitalSignature( $parameters, $request->header('base64signature'), base64_decode($request->header('base64publickey')) ); return match($signature){ 1 => true, 0 => false, default => -1 }; }
步骤2:同步前端JSON生成规则
确保前端生成签名用的JSON字符串和后端完全一致,需对参数对象按键排序后再转JSON:
// 新增键排序函数 const sortObjectKeys = (obj: Record<string, any>): Record<string, any> => { return Object.keys(obj).sort().reduce((res, key) => { res[key] = obj[key]; return res; }, {} as Record<string, any>); }; // 生成签名前先处理参数 const params = { /* 你的请求参数 */ }; const sortedParams = sortObjectKeys(params); // 生成无空格、无额外转义的JSON字符串 const jsonStr = JSON.stringify(sortedParams); // 传入generateSignature2生成签名 const signature = generateSignature2(jsonStr, privateKeyPem);
额外检查项
- 公钥格式验证:后端解码后的公钥必须是标准PEM格式(包含
-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----),若前端传的是去除头尾的公钥内容,需在后端手动补全PEM头尾 - 填充方式一致性:前端forge默认使用PKCS#1 v1.5填充,后端
openssl_verify默认也是该填充方式,无需额外修改 - 字符编码:确保前后端处理字符串时都使用UTF-8编码,避免中文等非ASCII字符的编码差异
内容的提问来源于stack exchange,提问作者Hayfa chouchene
相关产品推荐
相关产品推荐

