You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

签名验证失败求助:存入数据库前成功取出后失败

问题根源:椭圆曲线签名对象的序列化错误

你遇到的问题不是MySQL排序规则导致的,核心原因是直接对elliptic库生成的签名对象做了JSON.stringify序列化,从数据库取出JSON.parse后得到的只是普通JavaScript对象,并非原始的Signature实例,这就导致verify方法无法正确验证签名。

为什么会这样?

ec.sign()返回的是elliptic库的Signature类实例,这个对象不仅包含r、s等属性,还带有库内部的方法和类型标识。当你用JSON.stringify()序列化它时,只会保留可枚举的普通属性(比如r和s的字符串形式),但丢失了对象的原型链和内部结构。而publicKeyPair.verify()方法需要的是一个完整的Signature实例,不是普通的JSON对象,所以验证自然失败。

正确的解决方案:序列化签名为标准格式字符串

椭圆曲线签名通常可以序列化为DER格式的十六进制字符串(密码学领域的标准格式),而不是直接序列化对象。修改你的代码如下:

1. 存入数据库时:将签名转为DER十六进制字符串

// 替换原来的JSON.stringify(signature)
var signatureHex = signature.toDER('hex');
var post = { 
  host: host, 
  type: select, 
  value: value, 
  signature: signatureHex, // 存储十六进制字符串
  public : publicKey, 
  hash: message 
};

2. 从数据库取出时:将十六进制字符串还原为Signature实例

// 替换原来的JSON.parse(result[0].signature)
var signatureHex = result[0].signature;
var signature = ec.signatureFromDER(signatureHex, 'hex'); // 还原为Signature对象

const isVerified = verify(hash, public, signature);
console.log('> Is verified: ', isVerified); // 现在应该返回true了

额外验证:排除MySQL影响

如果还是担心MySQL的问题,可以确认你的signature字段类型是TEXT或者VARCHAR(255)(DER格式的椭圆曲线签名一般在70字节左右,转成十六进制是140字符,完全足够),排序规则用utf8mb4_general_ci或者ascii_general_ci都可以——因为十六进制字符都是ASCII范围内的,不会有编码问题。

补充说明

如果你不想用DER格式,也可以用signature.toString('hex')来序列化(这会把r和s拼接成一个长字符串),取出时用ec.signatureFromHex(signatureHex)来还原,但DER格式是更通用的标准,推荐使用。

内容的提问来源于stack exchange,提问作者Peter Štieber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:30:23