添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
·  阅读

前端和后端都有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.htmljsencrypt.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>
    复制代码
    分类:
    前端