предисловие
-
Эта статья в основном через
非对称加密
а такжеHMACSHA256
для шифрования данных -
В нашем фактическом процессе разработки мы обычно напрямую передаем данные в виде открытого текста в фоновый режим при выполнении запросов на получение и отправку. Конечно, нет проблем в развитии системы управления фоном компании.
-
Если мы по-прежнему используем открытый текст для передачи данных при разработке веб-страниц для внешнего использования, преступники очень легко могут быть перехвачены и изменены.
-
Впереди высокая энергия, пожалуйста, смотрите картинку ниже
- Например, мы отправляем запрос, а эффект, который мы хотим получить, это соусообразные капли (Сестрица Фея)
- В процессе запроса ответа преступники перехватили наш ответ с помощью ряда грубых операций.
- И модифицировал перехваченную информацию и вернул ее на передний край
- Когда пользователь увидел эту картинку, он моментально рухнул: Боже мой, верните мне мою сестру-фею.
-
Этот вид спуфа не самый страшный.Страшно то, что при выполнении операции перевода преступники подделали данные в процессе запроса и изменили их на перевод 100 миллионов себе (сначала поставили ему маленькую цель). Не будет ли это концом теленка. В это время я должен чувствовать себя соусом
-
Я не уверен, что босс вознаградит вас N+1
-
На данный момент думайте, что все поняли важность шифрования данных.Далее давайте поговорим о том, как мы должны с этим бороться в Nodejs.
Преамбула
-
Стек технологий, используемый в фоновом режиме,
+ express
-
Стек передовых технологий
+ vite + vue3 + axios + jsencrypt + crypto-js
Установите и запустите проект
1.1, сторона узла
- Создайте новую папку для выполнения
yarn add express
- Создайте app.js в корневом каталоге
const fs = require("fs") const path = require("path") const crypto = require("crypto") // node自带的密码相关的模块 const express = require("express") const app = new express() // 实例化 express const router = express.Router() // 创建理由 router.get("/api/get", (req, res) => { res.json([{ name: '张三', age: 28 },{ name: '李四', age: 24 }]) }) app.use(router) //将路由注入到 express中 // 启动服务 const port = 5555 app.listen(port,() => { console.log("server running: 127.0.0.1:" + port); })
- Стартовый проект
nodemon ./app.js
1.2. Запуск внешнего проекта
- Установить
vite
npm init @vitejs/app
- Создайте инженерный каталог и установите зависимости
npm init @vitejs/app client --template vue cd client yarn add axios jsencrypt crypto-js yarn install
- Исправлять
vite.config.js
Добавить обратный проксиimport { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], server: { proxy:{ '/api': 'http://localhost5555' } }, })
- Создан в каталоге src
utils/http.js
настраиватьaxios
перехватчикimport axios from 'axios' //请求拦截 axios.interceptors.request.use(function (config) { return config; }, function (error) { return Promise.reject(error); }); // 响应拦截 axios.interceptors.response.use(function (response) { return response; }, function (error) { return Promise.reject(error); }); export default axios
- Далее переделывать
app.vue
<template> <div> <ul> <li v-for="(item, idx) in info.getData" :key="idx"> <span>{{item.name}}</span> <span>{{item.age}}</span> </li> </ul> </div> </template> <script setup> import { reactive } from 'vue' import http from './utils/http' const info = reactive({ getData: [] }) http({ url: '/api/get', method: 'get', params: { name: '张三', age: '18' } }).then(res => { info.getData = res.data }) </script>
- Последний шаг перед рассветом, начните посещение проекта
localhost:3000
yarn dev
- Когда мы видим эту страницу, это доказывает, что первый шаг сделан
2. Логика шифрования
- Давайте взглянем на логику всего процесса шифрования. Предотвратить подделку данных незаконными элементами в процессе отправки запроса и ответа на него.
- Сначала при запуске клиента отправляется запрос на получение открытого ключа, который хранится локально в браузере (
sessionStorage、Storage
) все в порядке, на этот раз мы существуемsessionStorage
,
Затем, когда мы отправляем данные, мы сначала передаемHMACSHA256
Выполните проверку подлинности хэш-сообщения для данных, чтобы получить строку необратимых строк, а затем зашифруйте строку с помощью открытого ключа, который мы запросили обратно через асимметричное шифрование. Отправить в фон через заголовок запроса
- За кулисами
- Когда пользователь запрашивает открытый ключ,
- Во-первых, нам нужно определить, есть ли файл открытого ключа в проекте и каталоге, и если да, то вернуть содержимое файла открытого ключа напрямую.
- Если открытый ключ и закрытый ключ не созданы, вернуть открытый ключ
- Затем вам нужно написать промежуточное программное обеспечение, чтобы определить, какие маршруты не нуждаются в проверке.
- Например, интерфейс для получения открытого ключа не требует проверки, а интерфейс, не требующий проверки, сразу освобождается.
- Для маршрута, который необходимо проверить, мы получаем информацию заголовка запроса и расшифровываем ее с помощью закрытого ключа, соответствующего открытому ключу.
получите
HMACSHA256
Аутентифицированная строка. Далее мы используемHMACSHA256
Такая же аутентификация сообщения выполняется для параметров открытого текста. Сравните, согласуется ли расшифрованная строка аутентификации со строкой аутентификации, сгенерированной вами. Если они согласуются, это доказывает, что данные не были подделаны, и выполняет операцию освобождения. В противном случае возвращается соответствующее сообщение об ошибке.
- Когда пользователь запрашивает открытый ключ,
3. Шифрование и дешифрование
3.1. Интерфейс через/api/getpubkey
Интерфейс для получения открытого ключа
http({
url: '/api/getpubkey',
method: 'get',
}).then(res => {
sessionStorage.setItem("pubKey",res.data.data)
})
3.2, код, связанный с фоном, выглядит следующим образом.
const { execSync } = require('child_process'); //execSync方法主要是允许我们在node中写linux命令
const resolve = _path => path.resolve(__dirname, _path)
router.get("/api/getpubkey", (req, res) => {
//1. 读取公钥文件
let resPublicKey = ''
try {
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
} catch (error) {
//文件不存在则创建
execSync("openssl genrsa -out rsa_private.key 1024")
execSync('openssl rsa -in rsa_private.key -pubout -out rsa_public.key')
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
}
// 返回信息
res.json({
status: 0,
data: resPublicKey
})
})
3.3, передняя частьhttp.js
шифрование данных
import axios from 'axios'
import jsencrypt from 'jsencrypt'
import hmacsha256 from 'crypto-js/hmac-sha256'
const HMACSHA256KEY = '1001'
function hashSHA246(params) {
// 通过 hmacsha256 生成散列字符串
return hmacsha256(JSON.stringify(params), HMACSHA256KEY).toString()
}
//请求拦截
axios.interceptors.request.use(function (config) {
const excludesArr = ['/api/getpubkey']
const { url, params,data, method } = config
if(!excludesArr.includes(url)) {
let Authorization = ''
if (method === "get" && params) {
Authorization = hashSHA246(params)
}else if (method === "post" && data) {
Authorization = hashSHA246(data)
}
// 获取保存的公钥
const pubKey = sessionStorage.getItem("pubKey")
//实例化 jsencrypt
const JSencrypt = new jsencrypt()
// 对实例化对象设置公钥
JSencrypt.setPublicKey(pubKey)
// 通过公钥对数据加密
const encrypt = JSencrypt.encrypt(Authorization)
// 加密数据添加到请求头中
config.headers.common['Authorization'] = encrypt
}
return config;
}, function (error) {
return Promise.reject(error);
});
// 响应拦截
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
export default axios
3.4 Расшифровка промежуточного ПО узла
const fs = require("fs")
const path = require("path")
const crypto = require("crypto") // node自带的密码相关的模块
const { execSync } = require('child_process'); //execSync方法主要是允许我们在node中写linux命令
const express = require("express")
const app = new express() // 实例化 express
const router = express.Router() // 创建理由
const resolve = _path => path.resolve(__dirname, _path)
// 中间件
app.use((req, res, next) => {
const HMACSHA256KEY = '1001'
// 过滤不需要验证的接口
const excludesArr = ['/api/getpubkey']
const { originalUrl } = req
if (!excludesArr.includes(originalUrl)) {
// 读取请求头消息
const Authorization = req.get('Authorization')
if (Authorization) {
let de_res = {
status: 1,
message: '数据被篡改'
};
try {
const decryptText = crypto.privateDecrypt({
key: fs.readFileSync(resolve("./rsa_private.key")),
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(Authorization, "base64")).toString()
try {
if (decryptText) {
let hash = crypto.createHmac("sha256", HMACSHA256KEY)
const { method, query, body } = req
const obj = {
GET: query,
POST: body
}
let hashed = hash.update(JSON.stringify(obj[method])).digest("hex").toString()
console.log(hashed,decryptText);
if (hashed === decryptText) {
de_res = {
status: 0,
message: '通过'
}
} else {
console.log('hash摘要不相等');
}
} else {
console.log("缺少参数message和date");
}
} catch (error) {
console.log(error);
}
} catch (error) {
console.log(error);
}
if(de_res.status === 0) {
next()
}else {
res.json(de_res)
}
} else {
res.json({
status: 1,
message: 'Authorization 不能为空'
})
}
} else {
//放行
next()
}
})
router.get("/api/getpubkey", (req, res) => {
//1. 读取公钥文件
let resPublicKey = ''
try {
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
} catch (error) {
//文件不存在则创建
execSync("openssl genrsa -out rsa_private.key 1024")
execSync('openssl rsa -in rsa_private.key -pubout -out rsa_public.key')
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
}
// 返回信息
res.json({
status: 0,
data: resPublicKey
})
})
router.get("/api/get", (req, res) => {
res.json([{
name: '张三',
age: 28
}, {
name: '李四',
age: 24
}])
})
app.use(router) //将路由注入到 express中
// 启动服务
const port = 5555
app.listen(port, () => {
console.log("server running: 127.0.0.1:" + port);
})
- К этому времени запрошенные шифрование и дешифрование были написаны. Маме больше не нужно беспокоиться о подделке запросов данных,
Следующим шагом является настройка предотвращения фальсификации ответа.
3.5 Окончательный код проверки ответа на запрос внешнего интерфейса и внутреннего интерфейса
- внешний интерфейс
- http.js
import axios from 'axios' import jsencrypt from 'jsencrypt' import hmacsha256 from 'crypto-js/hmac-sha256' const HMACSHA256KEY = '1001' function hashSHA246(params) { // 通过 hmacsha256 生成散列字符串 return hmacsha256(JSON.stringify(params), HMACSHA256KEY).toString() } //请求拦截 axios.interceptors.request.use(function (config) { const excludesArr = ['/api/getpubkey'] const { url, params,data, method } = config if(!excludesArr.includes(url)) { let Authorization = '' if (method === "get" && params) { console.log(params); Authorization = hashSHA246(params) }else if (method === "post" && data) { Authorization = hashSHA246(data) } // 获取保存的公钥 const pubKey = sessionStorage.getItem("pubKey") //实例化 jsencrypt const JSencrypt = new jsencrypt() // 对实例化对象设置公钥 JSencrypt.setPublicKey(pubKey) console.log(Authorization); // 通过公钥对数据加密 const encrypt = JSencrypt.encrypt(Authorization) // 加密数据添加到请求头中 config.headers.common['Authorization'] = encrypt } return config; }, function (error) { return Promise.reject(error); }); // 响应拦截 axios.interceptors.response.use(function (response) { if (response.headers?.authorization) { const { authorization } = response.headers console.log(response.data); const decrypt = hmacsha256(JSON.stringify(response.data.data), HMACSHA256KEY).toString() if (decrypt === authorization) { console.log("数据是安全的"); return response } else { alert("数据被篡改了") } } else { return response } }, function (error) { return Promise.reject(error); }); export default axios
- app.vue
<template> <div> <button @click="sendGet">get</button> <button @click="sendPost">post</button> <ul> <li v-for="(item, idx) in info.getData" :key="idx"> <span>{{ item.name }}</span> <span>{{ item.age }}</span> </li> </ul> </div> </template> <script setup> import { reactive } from "vue"; import http from "./utils/http"; const info = reactive({ getData: [], }); http({ url: "/api/getpubkey", method: "get", }).then((res) => { sessionStorage.setItem("pubKey", res.data.data); }); function sendGet() { http({ url: "/api/get", method: "get", params: { name: "张三", age: "18", }, }).then((res) => { info.getData = res.data.data; }); } function sendPost() { http({ url: "/api/post", method: "post", data: { name: "张三", age: "18", }, }).then((res) => { info.getData = res.data.data; }); } </script>
- задняя часть
const fs = require("fs")
const path = require("path")
const crypto = require("crypto") // node自带的密码相关的模块
const { execSync } = require('child_process'); //execSync方法主要是允许我们在node中写linux命令
const express = require("express")
const app = new express() // 实例化 express
const router = express.Router() // 创建理由
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
const resolve = _path => path.resolve(__dirname, _path)
// hmac_sha256秘钥
const HMACSHA256KEY = '1001'
// 中间件
app.use((req, res, next) => {
// 过滤不需要验证的接口
const excludesArr = ['/api/getpubkey']
const { originalUrl } = req
if (!excludesArr.includes(originalUrl)) {
// 读取请求头消息
const Authorization = req.get('Authorization')
if (Authorization) {
let de_res = {
status: 1,
message: '数据被篡改'
};
try {
const decryptText = crypto.privateDecrypt({
key: fs.readFileSync(resolve("./rsa_private.key")),
padding: crypto.constants.RSA_PKCS1_PADDING
}, Buffer.from(Authorization, "base64")).toString()
try {
if (decryptText) {
let hash = crypto.createHmac("sha256", HMACSHA256KEY)
const { method, query, body } = req
const obj = {
GET: query,
POST: body
}
let hashed = hash.update(JSON.stringify(obj[method])).digest("hex").toString()
console.log(hashed,decryptText);
if (hashed === decryptText) {
de_res = {
status: 0,
message: '通过'
}
} else {
console.log('hash摘要不相等');
}
} else {
console.log("缺少参数message和date");
}
} catch (error) {
console.log(error);
}
} catch (error) {
console.log(error);
}
if(de_res.status === 0) {
next()
}else {
res.json(de_res)
}
} else {
res.json({
status: 1,
message: 'Authorization 不能为空'
})
}
} else {
//放行
next()
}
})
router.get("/api/getpubkey", (req, res) => {
//1. 读取公钥文件
let resPublicKey = ''
try {
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
} catch (error) {
//文件不存在则创建
execSync("openssl genrsa -out rsa_private.key 1024")
execSync('openssl rsa -in rsa_private.key -pubout -out rsa_public.key')
resPublicKey = fs.readFileSync(resolve('./rsa_public.key')).toString()
}
// 返回信息
res.json({
status: 0,
data: resPublicKey
})
})
/**
* 通过 hmacsha256加密要返回的数据
* @param {数据} data
* @returns
*/
function setResHead(data) {
return crypto.createHmac("sha256", HMACSHA256KEY).update(JSON.stringify(data)).digest().toString("hex")
}
router.get("/api/get", (req, res) => {
let data = [{
name: '张三',
age: 28
}, {
name: '李四',
age: 24
}]
res.set("Authorization",setResHead(data))
res.json({
status:0,
data
})
})
router.post("/api/post", (req, res) => {
let postData = [{
name: '王五',
age: 28
}, {
name: '赵六',
age: 24
}]
res.set("Authorization",setResHead(postData))
res.json({
status:0,
data: postData
})
})
app.use(router) //将路由注入到 express中
// 启动服务
const port = 5555
app.listen(port, () => {
console.log("server running: 127.0.0.1:" + port);
})
напиши в конце
- Когда вы это видите, во-первых, вы очень настойчивый человек.В этой статье мало иллюстраций, и в основном это работа.Если вы прочитали ее от начала до конца, поставьте себе лайк.
- В этой статье в основном рассказывается о том, зачем нужно шифрование и как шифровать
- Вышеупомянутое 🌰 в основном для того, чтобы вы начали
- Приветствую всех желающих прокомментировать проблему шифрования