前端和后端都有RSA加密库,但是通常不能通用,即浏览器的RSA库不能用在Node,Node的RSA库不能用在浏览器。在前后端之间进行RSA加密通信时,需要两端的库的配置相匹配。
本文以前端的 jsencrypt 库和后端的原生 crypto 库举例,讨论下前后端RSA加密通信的方法。
后端生成公钥和密钥
我们首先建立一个服务器:
import Express from 'express'
import Path from 'path'
import BodyParser from 'body-parser'
const cwd = globalThis.process.cwd()
const express = new Express()
const router = new Express.Router()
router.get('/', async (req, res) => {
res.sendFile(Path.resolve(cwd, './index.html'))
router.get('/jsencrypt.js', (req, res) => {
res.sendFile(Path.resolve(cwd, './lib/jsencrypt.js'))
express.use(BodyParser.text())
express.use(router)
express.listen(8000)
服务器提供了index.html
和jsencrypt.js
文件。
接下来用crypto库来创建公钥和密钥:
import Crypto from 'crypto'
const { publicKey, privateKey } = Crypto.generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: ''
Crypto.generateKeyPairSync文档:nodejs.cn/api/crypto.…
因为 jsencrypt 库的要求,公钥和密钥的配置必须如此。主要是 1024
未的公钥长度(modulusLength)和 spki
的编码方式。
然后配置一个获取公钥的路由:
router.get('/key', (req, res) => {
res.send(publicKey)
前端获取公钥并加密明文
在浏览器端,我们先引入 jsencrypt:
<script src="/jsencrypt.js"></script>
接下来获取公钥:
let publicKey = await (await fetch('/key')).text()
使用 jsencrypt 加密:
const value = 'Hack the world'
let jsEncrypt = new JSEncrypt()
jsEncrypt.setPublicKey(publicKey)
let result = jsEncrypt.encrypt(value)
把加密后的文本发送到后端,看后端能否解密:
let res = await (
await fetch('/encrypt', {
method: 'POST',
body: result
).text()
后端接收到密文后使用密钥解密:
router.post('/encrypt', (req, res) => {
let value = Crypto.privateDecrypt(
key: privateKey,
passphrase: '',
padding: Crypto.constants.RSA_PKCS1_PADDING
Buffer.from(req.body, 'base64')
res.send(value)
注意这里的配置:
padding: Crypto.constants.RSA_PKCS1_PADDING
Buffer.from(req.body, 'base64')
仍然是为了和 jsencrypt 配合而不能配置为其它值。
如果后端返回了 Hack the world
,那么久说明整个加解密的过程成功了。
样例代码:
import Express from 'express'
import Path from 'path'
import BodyParser from 'body-parser'
import Crypto from 'crypto'
const cwd = globalThis.process.cwd()
const express = new Express()
const router = new Express.Router()
const { publicKey, privateKey } = Crypto.generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: ''
console.log('> Private key')
console.log(privateKey)
router.get('/', async (req, res) => {
res.sendFile(Path.resolve(cwd, './index.html'))
router.get('/jsencrypt.js', (req, res) => {
res.sendFile(Path.resolve(cwd, './lib/jsencrypt.js'))
router.get('/key', (req, res) => {
res.send(publicKey)
router.post('/encrypt', (req, res) => {
let value = Crypto.privateDecrypt(
key: privateKey,
passphrase: '',
padding: Crypto.constants.RSA_PKCS1_PADDING
Buffer.from(req.body, 'base64')
res.send(value)
express.use(BodyParser.text())
express.use(router)
express.listen(8000)
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="/jsencrypt.js"></script>
<script type="module">
const value = 'Hack the world'
console.log('> Text')
console.log(value)
let publicKey = await (await fetch('/key')).text()
console.log('> Public key')
console.log(publicKey)
let jsEncrypt = new JSEncrypt()
jsEncrypt.setPublicKey(publicKey)
let result = jsEncrypt.encrypt(value)
console.log('> Encrypted text')
console.log(result)
let res = await (
await fetch('/encrypt', {
method: 'POST',
body: result
).text()
console.log('> Decrypted text')
console.log(res)
</script>
</head>
<body> </body>
</html>
复制代码