Go与Ruby跨语言RSA签名验证失败问题排查
问题根源与解决方案:Go签名Ruby验证失败的核心原因
核心问题:签名与验证的数据源不匹配
你的Go代码中,签名操作是对原始JSON序列化后的字节流进行哈希和签名:
func (r request) Signature(key *rsa.PrivateKey) string { data, err := json.Marshal(&r) // 处理原始JSON字节流 if err != nil { panic(err) } hashed := sha256.Sum256(data) // ...签名逻辑 }
但Ruby端验证时,直接用Base64编码后的字符串作为验证数据源:
return p_key.verify('sha256', Base64.strict_decode64(signature), message)
两者处理的核心数据完全不一致,这是验证失败的根本原因。
两种修复方案
方案1:修改Ruby端(推荐,保持Go端逻辑不变)
将接收到的Base64编码消息解码为原始JSON字节流,再进行验证:
def validate(public_key, message, signature) p_key = OpenSSL::PKey::RSA.new(public_key) # 解码Base64得到原始JSON数据,作为验证的核心数据源 original_data = Base64.strict_decode64(message) return p_key.verify('sha256', Base64.strict_decode64(signature), original_data) end
方案2:修改Go端(保持Ruby端逻辑不变)
调整Go的签名逻辑,对Base64编码后的字符串进行哈希和签名:
func (r request) Signature(key *rsa.PrivateKey) string { // 先获取Base64编码后的字符串 encoded := r.ToBase64() // 对Base64字符串进行哈希 hashed := sha256.Sum256([]byte(encoded)) signature, err := rsa.SignPKCS1v15(nil, key, crypto.SHA256, hashed[:]) if err != nil { panic(err) } return base64.StdEncoding.Strict().EncodeToString(signature) }
额外排查要点
- JSON序列化一致性:确保Go和Ruby的JSON输出完全一致(字段顺序、空格、引号格式等)。可分别打印两边原始JSON字节流的SHA256哈希值对比:
- Go端:
fmt.Printf("%x", sha256.Sum256(data)) - Ruby端:
puts Digest::SHA256.hexdigest(original_data)
若哈希值不同,需统一序列化规则(比如Ruby使用JSON.generate而非to_json,避免额外空格)。
- Go端:
- Base64编码一致性:你当前代码已使用
strict模式(无换行、标准字符集),这部分无需调整。 - 密钥格式:确认公钥为PKCS#1格式,Go的
x509.ParsePKCS1PrivateKey与Ruby的OpenSSL::PKey::RSA.new格式匹配,这部分逻辑是正确的。
内容的提问来源于stack exchange,提问作者lfrg
相关产品推荐
相关产品推荐

