实践:使用jsencrypt配合axios实现非对称加密传输数据

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 实践:使用jsencrypt配合axios实现非对称加密传输数据

背景


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


网络异常,图片无法展示
|


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

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


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

网络异常,图片无法展示
|


加密方案简述


对称加密

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

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


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


非对称加密


有公钥私钥之分:


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


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


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


本文选用 RSA 对称加密算法


公私钥生成


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


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

私钥


openssl genrsa -out rsa_1024_priv.pem 1024


点击查看生成私钥


-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQC0YiWffUFPnr2OyfcaM8QLkdq30VQxjIctZJX/CnYn7NorwCyK
iBX3hULSUrBxBACZBtfeGtpT+I9yn3+6s4kClZiJNOOP8bvJab4fboLUtJt9XciK
ENRxHVcnrYMrM+0diXGH/COjeA7ym/L2M/eX1fxpZjTByaJdx0FZAlrD4wIDAQAB
AoGBAKarxU2vw4gZCdeE3/BzAmMaWrjcD2pVCZY0ya/Fb9WGMTSZtc4u3fU+Sbbi
tqtGYnMC8rUDpNZP5eOoYrIVL7MJFj7n5DIT6TJOxWRavWsei812pQlc6ccR/VEH
o0nN5JQRZH8DC+CE86QddOW7VfnRMIP4A7j8UEEiRxsPITExAkEA4N10W/HA7lYE
WKSRES4/gAJHg7cqS2dAWIovX/JtxzUyK2q50rWjbgbXXOGriIp3cRJeH2Jmi6tm
jQQ+ldWAqwJBAM1b/9cRLWJ6fPdDIjbrc9IQE6C5HYI0FsHuyCn3zUKnD1+hc7k5
+BrSpyG5VzdPH3WOhm6GJ5TCf/LlxvvIeakCQQCEO1Ywt2KYBTc7FVNFgifPVAfP
+gdCHi6lomUni/1oVuzwwSsTMMMxcY51zTM88Qg6Eu4MkKXy3lFI/cT8AXhPAkEA
vy4q27muGsQVmsvxClfgl2tIGpS7l/+OQDVgO1Hq0WZdtZXE+mexRqdd2NOHEoKi
svpgxHw4VRFNtH+d48EbIQJBAMcLRGOuUrPhyYXmvEvvGGqcFH7zwjoyYlQQYR3a
IeAC4Mo/vDo7agLXvlRFXgPWMXAJqzjVhZ+xmew4hUqe5HY=
-----END RSA PRIVATE KEY-----


公钥


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


点击查看生成的公钥


-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0YiWffUFPnr2OyfcaM8QLkdq3
0VQxjIctZJX/CnYn7NorwCyKiBX3hULSUrBxBACZBtfeGtpT+I9yn3+6s4kClZiJ
NOOP8bvJab4fboLUtJt9XciKENRxHVcnrYMrM+0diXGH/COjeA7ym/L2M/eX1fxp
ZjTByaJdx0FZAlrD4wIDAQAB
-----END PUBLIC KEY-----


jsencrypt



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


使用


安装依赖


# web
npm i jsencrypt
# node
npm i nodejs-jsencrypt


引入


// web
import JSEncrypt from 'jsencrypt'
// node
const { JSEncrypt } = require('nodejs-jsencrypt')


公钥加密方法


// 上述自动生成
const pubKey = '上述生成的公钥'
function publicEncrypt(str){
    const encrypt = new JSEncrypt()
    encrypt.setPublicKey(pubKey)
    return encrypt.encrypt(str)
}


私钥解密方法


const privKey = `上述生成的私钥`
function privDecrypt(str) {
    const encrypt = new JSEncrypt()
    encrypt.setPrivateKey(privKey)
    return encrypt.decrypt(str)
}


可以看出API非常简洁


使用示例


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


结合Axios实践


Axios配置


npm i axios


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


import axios from "axios";
// 引入刚刚编写的加密方法
import { publicEncrypt } from "./utils/crypto";
const http = axios;
http.defaults.baseURL = '/api'
http.defaults.headers = {
  "content-Type": "application/json"
};
// 请求拦截器
http.interceptors.request.use(
  config => {
    // 发送之前操作config
    // 对传递的 data 进行加密
    config.data = {
      value:publicEncrypt(JSON.stringify(config.data))
    }
    return config;
  },
  err => {
    // 处理错误
    return Promise.reject(err);
  }
);
http.interceptors.response.use(
  response => {
    // 返回前操作
    return response.data;
  },
  err => {
    return Promise.reject(err);
  }
);
export default http;


服务端解密示例代码


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


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


http模块示例


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


const http = require('http')
// 引入解密方法
const { privDecrypt } = require('./utils/crypto')
const server = http.createServer((req, res) => {
    res.setHeader('content-type','application/json')
    let buffer = Buffer.alloc(0)
    // 接收传递的数据
    req.on('data',(chunk)=>{
        buffer = Buffer.concat([buffer, chunk])
    })
    req.on('end',()=>{
        try {
            // 解密传递的数据
            const data = privDecrypt(JSON.parse(buffer.toString('utf-8')).value)
            res.end(data)
        } catch (error) {
            console.log(error);
            res.end('error')            
        }
    })
})
// 启动
server.listen(3000, err => {
    console.log(`listen 3000 success`);
})


Express示例


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


const express = require('express')
const { privDecrypt } = require('./utils/crypto')
const server = express()
server.use(express.urlencoded({ extended: false }))
server.use(express.json({ strict: true }))
// 首先进入的路由
server.route('*').all((req, res, next) => {
    console.log(`${req.method}--${req.url}`)
    req.body = JSON.parse(privDecrypt(req.body.value))
    next()
})
server.post('/test/demo',(req,res)=>{
    // 直接返回实际的内容
    res.json(req.body)
})
// 启动
server.listen(3000, err => {
    console.log(`listen 3000 success`);
})
复制代码

前端代码示例


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

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


export default {
    server: {
        proxy: {
            '/api': {
                target: 'http://localhost:3000',
                changeOrigin: true,
                rewrite: (path) => path.replace(/^\/api/, '')
            },
        }
    }
}


页面


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


逻辑


import $http from './http'
const $send = document.getElementById('send')
const $receive = document.getElementById('receive')
$send.addEventListener('click',function(){
    // 发送一个随机内容
    $http.post('/test/demo',{
        name:'xm',
        age:~~(Math.random()*1000)
    }).then((res)=>[
        updateReceive(res)
    ])
})
function updateReceive(data){
    $receive.value = data instanceof Object?JSON.stringify(data):data
}


运行结果


页面


网络异常,图片无法展示
|


发送网络请求


网络异常,图片无法展示
|


请求响应内容


网络异常,图片无法展示
|


大工告成,接入十分简单


完整的示例代码仓库


欢迎评论交流


相关文章
|
1月前
|
存储 SQL 安全
加密后的数据如何进行模糊查询?
在数据安全和隐私保护日益重要的今天,加密技术成为保护敏感数据的重要手段。然而,加密后的数据在存储和传输过程中虽然安全性得到了提升,但如何对这些数据进行高效查询,尤其是模糊查询,成为了一个挑战。本文将深入探讨如何在保证数据安全的前提下,实现加密数据的模糊查询功能。
212 0
|
1月前
|
资源调度 JavaScript
|
3月前
|
Kubernetes Devops 持续交付
DevOps实践:使用Docker和Kubernetes实现持续集成和部署网络安全的守护盾:加密技术与安全意识的重要性
【8月更文挑战第27天】本文将引导读者理解并应用DevOps的核心理念,通过Docker和Kubernetes的实战案例,深入探讨如何在现代软件开发中实现自动化的持续集成和部署。文章不仅提供理论知识,还结合真实示例,旨在帮助开发者提升效率,优化工作流程。
|
3月前
|
存储 缓存 NoSQL
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
|
15天前
|
数据库 数据安全/隐私保护 Windows
Windows远程桌面出现CredSSP加密数据修正问题解决方案
【10月更文挑战第30天】本文介绍了两种解决Windows系统凭据分配问题的方法。方案一是通过组策略编辑器(gpedit.msc)启用“加密数据库修正”并将其保护级别设为“易受攻击”。方案二是通过注册表编辑器(regedit)在指定路径下创建或修改名为“AllowEncryptionOracle”的DWORD值,并将其数值设为2。
43 3
|
21天前
|
安全 网络安全 数据安全/隐私保护
网络安全与信息安全:从漏洞到加密,保护数据的关键步骤
【10月更文挑战第24天】在数字化时代,网络安全和信息安全是维护个人隐私和企业资产的前线防线。本文将探讨网络安全中的常见漏洞、加密技术的重要性以及如何通过提高安全意识来防范潜在的网络威胁。我们将深入理解网络安全的基本概念,学习如何识别和应对安全威胁,并掌握保护信息不被非法访问的策略。无论你是IT专业人士还是日常互联网用户,这篇文章都将为你提供宝贵的知识和技能,帮助你在网络世界中更安全地航行。
|
1月前
|
算法 安全 数据安全/隐私保护
加密和解密数据
【10月更文挑战第6天】加密和解密数据
48 2
|
1月前
|
JSON JavaScript 前端开发
axios的post请求,数据为什么要用qs处理?什么时候不用?
axios的post请求,数据为什么要用qs处理?什么时候不用?
|
1月前
|
安全 网络安全 数据安全/隐私保护
网络安全的守护者:漏洞管理与加密技术的实践之路
【9月更文挑战第33天】在数字时代的浪潮中,网络安全成为了维护信息资产安全的关键防线。本文将深入探讨网络安全中的两个核心要素——漏洞管理和加密技术,揭示它们如何协同工作以保护我们的在线世界。我们将通过实际案例,展示这些技术如何在现实世界中发挥作用,并强调安全意识的重要性。无论你是IT专业人士还是普通网民,这篇文章都将为你提供宝贵的知识和启示。
|
2月前
|
JavaScript 前端开发 安全
js逆向实战之烯牛数据请求参数加密和返回数据解密
【9月更文挑战第20天】在JavaScript逆向工程中,处理烯牛数据的请求参数加密和返回数据解密颇具挑战。本文详细分析了这一过程,包括网络请求监测、代码分析、加密算法推测及解密逻辑研究,并提供了实战步骤,如确定加密入口点、逆向分析算法及模拟加密解密过程。此外,还强调了法律合规性和安全性的重要性,帮助读者合法且安全地进行逆向工程。
89 11