引言
vue项目实现一个基本的接口加密非常简单,通过 axios 配合加密解密算法做请求、响应预处理。后端一样的操作,拦截器处理、网关处理也好,eBPF hook也罢,殊途同归。
接口加密的作用: 安全、防爬 等。悉知: 没有绝对安全的系统,只有破解成本的高低。
实现
首先创建一个vue项目,然后引入 axios、crypto-js
1 2
| yarn add crypto-js yarn add axios
|
前端目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| . ├── README.md ├── index.html ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.vue │ ├── apis │ │ └── httpdemo.js // 接口请求 │ ├── assets │ │ └── vue.svg │ ├── components │ │ └── HelloWorld.vue // 测试的页面 │ ├── main.js │ ├── style.css │ └── utils │ ├── AEScrypto.js //加解密方法 │ └── request.js // axios预处理 ├── vite.config.js └── yarn.lock
|
这篇文章主要是讲解思路,为了省事跟前面的文章 python RSA、AES 加密解密相关联,加密方法用AES的CBC padding7,别问为啥不用rsa,有长度限制。
AEScrypto.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import CryptoJS from 'crypto-js';
const secretKey = CryptoJS.enc.Utf8.parse('1234567812345678'); const iv = CryptoJS.enc.Utf8.parse('1234567812345678');
export function encrypt(data) { const encrypted = CryptoJS.AES.encrypt(data, secretKey, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); }
export function decrypt(encryptedData) { const decrypted = CryptoJS.AES.decrypt(encryptedData, secretKey, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); }
const originalData = 'Hello, World!';
const encryptedData = encrypt(originalData); console.log('Encrypted Data: ', encryptedData);
const decryptedData = decrypt(encryptedData); console.log('Decrypted Data: ', decryptedData);
|
request.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import axios from 'axios' import {encrypt, decrypt} from './AEScrypto.js' const service = axios.create({ baseURL: 'http://127.0.0.1:8002', timeout: 5000 })
service.interceptors.request.use( config => { console.log("明文请求体: ",config.data) const encryptData = encrypt(JSON.stringify(config.data)) console.log("密文消息体: ", encryptData) config.data = { "req": encryptData } return config; } )
service.interceptors.response.use( response => { console.log("密文响应体: ",response.data) const decryptData = JSON.parse(decrypt(response.data)) console.log("明文消息体: ", decryptData) response.data = decryptData return response; } )
export default service;
|
httpdemo.js
1 2 3 4 5 6 7 8 9 10
| import request from "../utils/request.js";
export function helloWordApi(data){ return request({ url: 'hello', method: "POST", data: data }) }
|
HelloWorld.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <template> <h1>{{ msg }}</h1> <input type="text" v-model="req_body"> <button @click="reqHello">请求api</button> <div class="code"> 请求体-明文<br> {{req_body}} <br> 响应体-明文<br> {{res_body}} <br> </div> </template>
<script setup> import { ref } from 'vue' import {helloWordApi} from "../apis/httpdemo.js";
defineProps({ msg: String, })
const req_body = ref() const res_body = ref() function reqHello(){
console.log('req_body', req_body.value) const api_data = JSON.parse(req_body.value) helloWordApi(api_data).then( res=>{ res_body.value = res.data console.log('res_body', res_body.value, typeof res.data) } ) }
</script>
<style scoped> .code{ background-color: #888888; } </style>
|
后端我省事使用flask写,跟前篇的charles自定义解密插件文章同理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
import json import time
from flask import Flask, request from flask_cors import CORS
from AESCipherUtils import AESCipher
app = Flask(__name__) CORS(app) aes = AESCipher()
@app.route('/hello', methods=['GET','POST']) def hello(): print("req body: ", request.json) res = json.loads(aes.decrypt(request.json['req'])) res['timestamp'] = int(time.time()) res = aes.encrypt(json.dumps(res)) print("res body: ", res) return res
@app.route('/decrypt', methods=['POST']) def decrypt(): data = {}
req_body_json = request.json try: data['req'] = aes.decrypt(req_body_json['req']) data['res'] = aes.decrypt(req_body_json['res'])
except Exception as error: data['error'] = str(error) return data
if __name__ == '__main__': app.run( port=8002, host="0.0.0.0", debug=True )
|
逻辑非常简单,axios 将密文请求体加密组装成 {"req":"加密后的密文"}
放在body中进行请求,后端解密后加个时间戳(模仿业务处理),加密返回。axios再对响应进行预处理。
演示