RSA 非对称加密是 Web 开发中最基础也最重要的安全基石之一。从 HTTPS 到 API 签名,从用户密码保护到支付数据加密,RSA 无处不在。然而很多开发者对 RSA 的理解停留在"公钥加密、私钥解密"的层面,在实际项目中频频踩坑。本文将通过 5 个真实场景,带你掌握 RSA 加密的实战技巧,并推荐 jsjson.com 的 RSA 在线工具 帮你快速调试验证。
📋 RSA 加密的核心原理速览
RSA 的安全性基于大数分解的数学难题。简单理解:
- 公钥(Public Key):可以公开分享,用于加密数据或验证签名
- 私钥(Private Key):必须严格保密,用于解密数据或生成签名
- 密钥长度:常见 1024 位、2048 位、4098 位,长度越长越安全但速度越慢
在实际项目中,RSA 的两大核心用途是数据加密和数字签名,两者方向相反:
| 场景 | 操作 | 用途 |
|---|---|---|
| 数据加密 | 公钥加密 → 私钥解密 | 保护数据传输安全 |
| 数字签名 | 私钥签名 → 公钥验证 | 验证身份和数据完整性 |
如果你需要快速生成 RSA 密钥对并测试加密解密流程,可以直接使用 jsjson.com 的 RSA 工具,支持 PKCS#1 和 PKCS#8 多种格式。
🔐 场景一:API 接口敏感数据加密
问题背景
在前后端分离的架构中,用户登录密码、身份证号、银行卡号等敏感信息如果明文传输,一旦被抓包就会泄露。即使使用了 HTTPS,在某些内网环境或调试场景下,额外的应用层加密仍然是必要的安全措施。
实战方案
前端流程:
1. 从后端获取 RSA 公钥(通常通过配置接口或环境变量注入)
2. 用户提交表单时,用公钥加密敏感字段
3. 将加密后的密文作为参数发送给后端
后端流程:
1. 接收到加密数据后,使用私钥解密
2. 对解密后的明文进行业务处理
前端 JavaScript 加密示例(使用 JSEncrypt 库):
import JSEncrypt from 'jsencrypt'
const encrypt = new JSEncrypt()
encrypt.setPublicKey(publicKey) // 设置后端返回的公钥
const encryptedPassword = encrypt.encrypt('用户密码明文')
// 将 encryptedPassword 发送给后端
调试技巧
在开发过程中,你经常需要验证"公钥加密后的数据能否被私钥正确解密"。这时不需要搭建完整的后端环境,直接用 jsjson.com 的 RSA 在线工具 就能完成验证:
- 生成或粘贴密钥对
- 用公钥加密测试数据
- 用私钥解密,确认结果与原文一致
- 再到项目代码中对接
这比写单元测试来调试加密逻辑要快得多。
🔏 场景二:JWT Token 签名与验证
为什么 JWT 需要 RSA
JWT(JSON Web Token)常用的签名算法有 HMAC 和 RSA 两种。当你的系统涉及多个服务(微服务架构)时,RSA 签名的优势就体现出来了:
- HMAC:所有服务都需要持有同一个密钥,密钥泄露风险高
- RSA:签名服务用私钥,验证服务只需要公钥,密钥暴露面小
实战配置
RS256 算法的 JWT 结构:
Header: {"alg": "RS256", "typ": "JWT"}
Payload: {"sub": "user123", "exp": 1719000000}
Signature: RSASHA256(base64(header) + "." + base64(payload), privateKey)
Node.js 示例(使用 jsonwebtoken 库):
const jwt = require('jsonwebtoken')
const fs = require('fs')
const privateKey = fs.readFileSync('private.pem')
const publicKey = fs.readFileSync('public.pem')
// 签发 Token
const token = jwt.sign({ sub: 'user123' }, privateKey, {
algorithm: 'RS256',
expiresIn: '24h'
})
// 验证 Token
const decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] })
常见坑点
密钥格式不匹配是新手最常遇到的问题。不同库对密钥格式的要求不同:
- PKCS#1 格式:
-----BEGIN RSA PRIVATE KEY----- - PKCS#8 格式:
-----BEGIN PRIVATE KEY-----
如果你遇到 “Invalid PEM formatted message” 错误,先用 jsjson.com 的 RSA 工具 检查密钥格式是否正确,工具支持多种格式之间的查看和验证。
🛡️ 场景三:文件与数据的数字签名
签名 vs 加密
很多人混淆"加密"和"签名"。核心区别:
- 加密是为了保密——让别人看不懂内容
- 签名是为了防篡改——让别人知道内容没被改过
在实际项目中,文件下载校验、API 请求防篡改、电子合同签署等场景都需要用到 RSA 数字签名。
实战场景:API 请求签名
很多开放平台(如支付宝、微信支付)要求对 API 请求进行 RSA 签名:
签名流程:
1. 将请求参数按字母排序拼接成字符串
2. 使用商户私钥对字符串进行 RSA-SHA256 签名
3. 将签名值附加到请求参数中
验签流程:
1. 收到回调后,提取签名值
2. 使用支付宝公钥对参数字符串验签
3. 验签通过则确认请求来自支付宝
Python 签名示例:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import base64
# 加载私钥
with open('private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
# 签名
message = b"app_id=123&method=pay×tamp=1719000000"
signature = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)
sign_base64 = base64.b64encode(signature).decode()
调试签名时,可以在 jsjson.com 的 RSA 工具 中分别测试加密和签名操作,确认密钥对工作正常后再集成到代码中。
🔄 场景四:密钥轮换与多版本管理
为什么要轮换密钥
密钥使用时间越长,被破解的风险越大。安全最佳实践要求定期更换 RSA 密钥。但轮换密钥不是简单地生成新密钥替换旧的——你需要考虑过渡期。
平滑轮换策略
时间线:
Day 0: 使用 Key-A 签名,验证用 Key-A 的公钥
Day 30: 生成 Key-B,开始用 Key-B 签名
验证时同时支持 Key-A 和 Key-B 的公钥
Day 60: 确认所有旧 Token 过期后,移除 Key-A
现在只用 Key-B
JWKS(JSON Web Key Set)是管理多版本公钥的标准方案:
{
"keys": [
{ "kid": "key-a", "kty": "RSA", "use": "sig", "n": "...", "e": "AQAB" },
{ "kid": "key-b", "kty": "RSA", "use": "sig", "n": "...", "e": "AQAB" }
]
}
Token 的 Header 中通过 kid 字段指定使用哪个密钥签名,验证方根据 kid 查找对应公钥。
密钥长度选择建议
| 密钥长度 | 安全性 | 性能 | 推荐场景 |
|---|---|---|---|
| 1024 位 | ⚠️ 已不安全 | 快 | 不推荐使用 |
| 2048 位 | ✅ 当前标准 | 适中 | 大多数场景 |
| 4096 位 | ✅ 高安全 | 慢 | 金融、政务等高安全要求 |
在 jsjson.com 的 RSA 工具 中,你可以测试不同密钥长度的生成速度和加密解密性能,帮助你做出合理的选择。
💡 场景五:RSA + AES 混合加密
为什么不能只用 RSA
RSA 有两个天然限制:
- 加密长度限制:2048 位密钥最多加密约 245 字节数据
- 性能较差:比对称加密慢 100-1000 倍
所以实际项目中,大数据量的加密通常采用 RSA + AES 混合方案:
加密流程:
1. 生成随机的 AES 密钥
2. 用 AES 密钥加密实际数据(快,支持任意长度)
3. 用 RSA 公钥加密 AES 密钥(短,RSA 够用)
4. 将两部分密文一起传输
解密流程:
1. 用 RSA 私钥解密出 AES 密钥
2. 用 AES 密钥解密实际数据
这是 HTTPS、PGP 加密邮件、加密文件传输等场景的标准做法。
前端实现示例:
async function hybridEncrypt(data, rsaPublicKey) {
// 1. 生成 AES 密钥
const aesKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true, ['encrypt', 'decrypt']
)
// 2. AES 加密数据
const iv = crypto.getRandomValues(new Uint8Array(12))
const encryptedData = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
aesKey,
new TextEncoder().encode(data)
)
// 3. 导出 AES 密钥并用 RSA 加密
const rawAesKey = await crypto.subtle.exportKey('raw', aesKey)
const encrypt = new JSEncrypt()
encrypt.setPublicKey(rsaPublicKey)
const encryptedKey = encrypt.encrypt(
btoa(String.fromCharCode(...new Uint8Array(rawAesKey)))
)
return { encryptedKey, encryptedData, iv }
}
❓ 常见问题 FAQ
RSA 加密的数据长度有限制吗?
是的。RSA 能加密的最大数据长度取决于密钥长度和填充方案。2048 位密钥使用 OAEP 填充最多加密约 190 字节,使用 PKCS#1 填充最多约 245 字节。如果需要加密更长的数据,请使用 RSA + AES 混合加密方案。
PKCS#1 和 PKCS#8 格式有什么区别?
PKCS#1 是 RSA 专用格式,密钥文件头为 -----BEGIN RSA PRIVATE KEY-----。PKCS#8 是通用私钥格式,支持多种算法,文件头为 -----BEGIN PRIVATE KEY-----。大多数现代库推荐使用 PKCS#8 格式。你可以在 jsjson.com 的 RSA 工具 中查看两种格式的区别。
RSA 密钥可以使用多少年?
NIST 建议 2048 位 RSA 密钥的有效期不超过 2030 年。对于新建系统,建议直接使用 2048 位并计划在 3-5 年内轮换。如果项目生命周期较长或安全要求较高,可以考虑使用 4096 位或迁移至 ECC(椭圆曲线加密)。
如何安全存储 RSA 私钥?
私钥绝不能硬编码在代码中或提交到 Git 仓库。推荐做法:使用环境变量、密钥管理服务(如 AWS KMS、HashiCorp Vault)、或加密的密钥文件。在开发调试阶段,可以使用 jsjson.com 的 RSA 工具 生成测试密钥对,避免使用生产环境的密钥。
RSA 和 ECC 该选哪个?
ECC(椭圆曲线加密)在相同安全强度下密钥更短、性能更好。256 位 ECC 约等同于 3072 位 RSA 的安全性。新项目推荐优先考虑 ECC,但 RSA 的生态更成熟,兼容性更好。如果项目需要对接老旧系统或第三方平台要求 RSA,那就用 RSA。
🔗 相关工具推荐
- MD5 在线加密工具 — 数据完整性校验,配合 RSA 签名使用
- SHA256 哈希计算工具 — RSA 签名算法通常搭配 SHA256 使用
- Base64 编解码工具 — RSA 密文通常以 Base64 格式传输
- 密码生成器 — 生成安全的密钥保护密码
- JSON 格式化工具 — 调试 JWT Token 和 API 响应时格式化 JSON 数据