SubtleCrypto 接口支持ECDSA等数字签名,需将数据转ArrayBuffer、密钥通过generateKey/importKey导入,私钥默认不可导出;签名验证须算法一致、公钥绑定身份,且仅限HTTPS/localhost安全上下文。

HTML5 中的 SubtleCrypto 接口可用于执行数字签名(如 ECDSA、RSA-PSS),但需注意:它不直接处理原始字符串,必须先将数据转为 ArrayBuffer,且密钥需通过 generateKey() 或 importKey() 正确导入,私钥不可导出(除非显式设为 extractable: true)。
生成密钥对并签名(以 ECDSA 为例)
ECDSA 是 Web 签名常用方案,轻量、速度快,适合前端签名场景:
- 调用
window.crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"])生成密钥对 - 使用
sign()方法签名时,需指定算法对象:{ name: "ECDSA", hash: "SHA-256" } - 待签名数据必须是
ArrayBuffer,可用new TextEncoder().encode("hello").buffer转换字符串 - 签名结果是
ArrayBuffer,通常转为 base64 或十六进制便于传输:arrayBufferToBase64(signature)
导入已有私钥进行签名(如 PEM 格式)
若后端已提供私钥(如 PEM 编码的 PKCS#8),需先去除头尾、base64 解码,再用 importKey() 导入:
- 移除
-----BEGIN PRIVATE KEY-----和换行符,解码为Uint8Array - 调用
crypto.subtle.importKey("pkcs8", keyData, { name: "ECDSA", namedCurve: "P-256" }, false, ["sign"]) -
false表示私钥不可导出,符合安全默认策略 - 注意:RSA 私钥需用
"pkcs8"格式;EC 私钥也统一用"pkcs8"(不是"jwk"或"spki")
签名验证流程(前端或后端配合)
签名本身不保证传输安全,验证环节必不可少:
立即学习“前端免费学习笔记(深入)”;
- 公钥可通过
exportKey("spki", publicKey)导出为 PEM 格式供服务端验证 - 前端验证示例:
crypto.subtle.verify("ECDSA", publicKey, signature, data),返回true/false - 服务端应使用相同算法(如 OpenSSL 的
openssl dgst -sha256 -verify pub.pem -signature sig.bin payload.txt)交叉校验 - 避免直接验证用户传来的公钥——应绑定身份(如 JWT 中嵌入 kid),防止密钥替换攻击
常见问题与规避方式
实际开发中容易踩坑,关键点如下:
-
跨域限制:
crypto.subtle只在安全上下文(HTTPS 或 localhost)可用,HTTP 页面会报错 -
异步陷阱:所有方法返回 Promise,勿漏掉
await或.then(),否则签名结果为 pending -
哈希不匹配:签名算法中的
hash必须与验证端一致,ECDSA 常用"SHA-256",RSA-PSS 可选"SHA-384" -
密钥复用风险:同一私钥不宜长期用于多业务,建议按场景分密钥,或结合
keyUsages严格限定用途











