使用Jsencrypt配合axios实现数据传输加密

[[404720]]

本文转载自微信公众号「粥里有勺糖」,作者粥里有勺糖。转载本文请联系粥里有勺糖公众号。

背景

不希望应用发送的数据能在 Devtools 中被看到,避免接口被“同行”扒下来,然后被恶意使用

要避免此问题,首先想到的就是对传输的数据进行一次加密,让后端自行解密然后处理

尽管js源码是被浏览器公开的,但通过构建工具混淆后,在没有source map的情况下还不不易定位目标代码

期望加密后的样子传输的内容如下

加密方案简述

对称加密

对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。

这种加密方式固然很好,但是问题就在于如何让双方知道秘钥。

由于传输数据都是走的网络,如果将秘钥通过网络的方式传递的话,一旦秘钥被截获就没有加密的意义

非对称加密

有公钥私钥之分:

  • 公钥所有人都可以知道,可以将数据用公钥加密,但是将数据解密必须使用私钥解密
  • 私钥只有分发放公钥的一方才知道

这种加密方式就可以完美解决对称加密存在的问题

通过对比,选用保密性好的 非对称加密 方案作为加密方案

本文选用 RSA[1] 对称加密算法

公私钥生成

根据百度经验的建议,生成一个1024位的的秘钥

这里使用openssl生成,window下建议在Git Bash下使用

私钥

  1. openssl genrsa -out rsa_1024_priv.pem 1024 

公钥

  1. openssl rsa -pubout -in rsa_1024_priv.pem -out rsa_1024_pub.pem 

jsencrypt

  • jsencrypt[2]
  • nodejs-jsencrypt[3]

“使用 Javascript 进行RSA加密的解决方案

使用

安装依赖

  1. # web 
  2. npm i jsencrypt 
  3.  
  4. # node 
  5. npm i nodejs-jsencrypt 

引入

  1. // web 
  2. import JSEncrypt from 'jsencrypt' 
  3.  
  4. // node 
  5. const { JSEncrypt } = require('nodejs-jsencrypt'

公钥加密方法

  1. // 上述自动生成 
  2. const pubKey = '上述生成的公钥' 
  3.  
  4. function publicEncrypt(str){ 
  5.     const encrypt = new JSEncrypt() 
  6.     encrypt.setPublicKey(pubKey) 
  7.     return encrypt.encrypt(str) 

私钥解密方法

  1. const privKey = `上述生成的私钥` 
  2.  
  3. function privDecrypt(str) { 
  4.     const encrypt = new JSEncrypt() 
  5.     encrypt.setPrivateKey(privKey) 
  6.     return encrypt.decrypt(str) 

可以看出API非常简洁

使用示例

  1. let str = publicEncrypt('hello world'
  2. console.log(str) 
  3. console.log(privDecrypt(str)) 

结合Axios实践

Axios配置

  1. npm i axios 

将加密逻辑放入到axios的请求拦截器中,将原内容使用 JSON.stringify处理后再进行加密,加密后的内容使用value属性传递,如下所示

  1. import axios from "axios"
  2.  
  3. // 引入刚刚编写的加密方法 
  4. import { publicEncrypt } from "./utils/crypto"
  5.  
  6. const http = axios; 
  7. http.defaults.baseURL = '/api' 
  8. http.defaults.headers = { 
  9.   "content-Type""application/json" 
  10. }; 
  11.  
  12. // 请求拦截器 
  13. http.interceptors.request.use( 
  14.   config => { 
  15.     // 发送之前操作config 
  16.     // 对传递的 data 进行加密 
  17.     config.data = { 
  18.       value:publicEncrypt(JSON.stringify(config.data)) 
  19.     } 
  20.     return config; 
  21.   }, 
  22.   err => { 
  23.     // 处理错误 
  24.     return Promise.reject(err); 
  25.   } 
  26. ); 
  27. http.interceptors.response.use( 
  28.   response => { 
  29.     // 返回前操作 
  30.     return response.data; 
  31.   }, 
  32.   err => { 
  33.     return Promise.reject(err); 
  34.   } 
  35. ); 
  36.  
  37. export default http; 

服务端解密示例代码

这里列举了两种,一种直接使用Node.js的http模块编写,一种使用Express编写:

  1. 解密收到的内容
  2. 将解密后的内容直接返回

http模块示例

使用data事件与end事件配合,接收传递的数据,然后进行解密返回

  1. const http = require('http'
  2.  
  3. // 引入解密方法 
  4. const { privDecrypt } = require('./utils/crypto'
  5.  
  6. const server = http.createServer((req, res) => { 
  7.     res.setHeader('content-type','application/json'
  8.     let buffer = Buffer.alloc(0) 
  9.  
  10.     // 接收传递的数据 
  11.     req.on('data',(chunk)=>{ 
  12.         buffer = Buffer.concat([buffer, chunk]) 
  13.     }) 
  14.     req.on('end',()=>{ 
  15.         try { 
  16.             // 解密传递的数据 
  17.             const data = privDecrypt(JSON.parse(buffer.toString('utf-8')).value) 
  18.             res.end(data) 
  19.         } catch (error) { 
  20.             console.log(error); 
  21.             res.end('error')             
  22.         } 
  23.     }) 
  24. }) 
  25.  
  26. // 启动 
  27. server.listen(3000, err => { 
  28.     console.log(`listen 3000 success`); 
  29. }) 

Express示例

配置一个前置的*路由,解密传递的内容,然后将其重新绑定到req.body上,供后续其它路由使用

  1. const express = require('express'
  2. const { privDecrypt } = require('./utils/crypto'
  3.  
  4. const server = express() 
  5.  
  6. server.use(express.urlencoded({ extended: false })) 
  7. server.use(express.json({ strict: true })) 
  8.  
  9. // 首先进入的路由 
  10. server.route('*').all((req, res, next) => { 
  11.     console.log(`${req.method}--${req.url}`) 
  12.     req.body = JSON.parse(privDecrypt(req.body.value)) 
  13.     next() 
  14. }) 
  15.  
  16. server.post('/test/demo',(req,res)=>{ 
  17.     // 直接返回实际的内容 
  18.     res.json(req.body) 
  19. }) 
  20.  
  21. // 启动 
  22. server.listen(3000, err => { 
  23.     console.log(`listen 3000 success`); 
  24. }) 

前端代码示例

使用了 Vite 作为开发预览工具

vite.config.js配置: 只做了请求代理,解决开发跨域问题

  1. export default { 
  2.     server: { 
  3.         proxy: { 
  4.             '/api': { 
  5.                 target: 'http://localhost:3000'
  6.                 changeOrigin: true
  7.                 rewrite: (path) => path.replace(/^\/api/, ''
  8.             }, 
  9.         } 
  10.     } 

页面

  1. <body> 
  2.     <button id="send">发送</button> 
  3.     <hr> 
  4.     <h2></h2> 
  5.     <textarea id="receive" placeholder="接收的内容"></textarea> 
  6.     <script type="module" src="./index.js"></script> 
  7. </body> 

 

 

逻辑

  1. import $http from './http' 
  2. const $send = document.getElementById('send'
  3. const $receive = document.getElementById('receive'
  4.  
  5. $send.addEventListener('click',function(){ 
  6.     // 发送一个随机内容 
  7.     $http.post('/test/demo',{ 
  8.         name:'xm'
  9.         age:~~(Math.random()*1000) 
  10.     }).then((res)=>[ 
  11.         updateReceive(res) 
  12.     ]) 
  13. }) 
  14.  
  15. function updateReceive(data){ 
  16.     $receive.value = data instanceof Object?JSON.stringify(data):data 

运行结果

页面

发送网络请求

请求响应内容

大功告成,接入十分简单

完整的示例代码仓库[4]

外链

[1]RSA: https://baike.baidu.com/item/RSA%E7%AE%97%E6%B3%95/263310

[2]jsencrypt: https://www.npmjs.com/package/jsencrypt

[3]nodejs-jsencrypt: https://www.npmjs.com/package/nodejs-jsencrypt

[4]完整的示例代码仓库: https://github.com/ATQQ/demos/tree/main/asymmetric-encryption

 

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/150580.html<

(0)
运维的头像运维
上一篇2025-03-13 03:43
下一篇 2025-03-13 03:44

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注