为何node-forge生成的签名在Spring Boot服务中验签失败?
问题根因
两个核心问题导致签名校验失败:
- 字节编码转换错误:node-forge返回的签名、哈希结果是latin1(binary)编码的二进制字符串,调用
Buffer.from()转换时没有指定编码,Node.js默认按UTF-8解析,会把单个值大于0x7F的字节转成2~3个字节,最终256字节的标准RSA2048签名膨胀到300多字节,触发长度错误。 - 签名验签逻辑不匹配:Java侧
SHA256withRSA是组合算法,会自动对传入的原始消息做SHA256哈希再执行验签,但Nuxt侧传给接口的encrypted参数是提前算好的SHA256摘要,Java侧会对这个32字节摘要再做一次哈希,就算长度正确也会验签不通过。
修复方案
Nuxt侧代码修正
调整签名逻辑,直接对原始消息签名,Buffer转换时明确指定编码:
var md = forge.md.sha256.create(); // 原始待签名消息,和认证服务侧约定内容保持一致,明确指定utf8编码避免多字节字符乱码 const originalMsg = "123"; md.update(originalMsg, 'utf8'); // 生成SHA256withRSA签名,返回latin1编码的二进制字符串 var sign = pPrivateKey.sign(md); // 转换时必须指定latin1编码,避免字节膨胀 var keyAuthB64Url = Buffer.from(originalMsg, 'utf8').toString("base64url"); var signB64Url = Buffer.from(sign, 'latin1').toString("base64url"); var jwt = await axios.get(process.env.URL + "/auth", { params: { encrypted: keyAuthB64Url, signature: signB64Url } });
Java侧代码说明
现有校验逻辑不需要修改,SHA256withRSA会自动处理消息哈希,和修正后的Nuxt侧逻辑完全对齐。
补充确认:RSA密钥对为2048位时,PKCS#1 v1.5填充的签名长度固定为256字节,和Java侧期望的长度一致,不需要调整密钥配置。
如果你有特殊业务需求必须传递消息摘要而非原始消息,需要将Java侧签名算法改为NONEwithRSA,手动拼接SHA256对应的PKCS#1 v1.5 DigestInfo前缀后再执行验签,该方案实现复杂度高容易出错,无特殊要求不建议使用。
内容的提问来源于stack exchange,提问作者Diop Saliou Alpha
相关产品推荐
相关产品推荐

