Используйте криптомодуль Node для реализации внешнего и внутреннего шифрования данных.

Node.js
Используйте криптомодуль Node для реализации внешнего и внутреннего шифрования данных.

предисловие

  • Эта статья в основном через非对称加密а такжеHMACSHA256для шифрования данных

  • В нашем фактическом процессе разработки мы обычно напрямую передаем данные в виде открытого текста в фоновый режим при выполнении запросов на получение и отправку. Конечно, нет проблем в развитии системы управления фоном компании.

  • Если мы по-прежнему используем открытый текст для передачи данных при разработке веб-страниц для внешнего использования, преступники очень легко могут быть перехвачены и изменены.

  • Впереди высокая энергия, пожалуйста, смотрите картинку ниже

    • Например, мы отправляем запрос, а эффект, который мы хотим получить, это соусообразные капли (Сестрица Фея)刘亦菲1.jpg
    • В процессе запроса ответа преступники перехватили наш ответ с помощью ряда грубых операций.黑客1.jpg
    • И модифицировал перехваченную информацию и вернул ее на передний край鼻毛女1.jpeg
    • Когда пользователь увидел эту картинку, он моментально рухнул: Боже мой, верните мне мою сестру-фею.
  • Этот вид спуфа не самый страшный.Страшно то, что при выполнении операции перевода преступники подделали данные в процессе запроса и изменили их на перевод 100 миллионов себе (сначала поставили ему маленькую цель). Не будет ли это концом теленка. В это время я должен чувствовать себя соусом

  • Я не уверен, что босс вознаградит вас N+1

    人傻了.jpeg

  • На данный момент думайте, что все поняли важность шифрования данных.Далее давайте поговорим о том, как мы должны с этим бороться в 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'
            }
          },
        })
    
    
  • Создан в каталоге srcutils/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
    
  • Когда мы видим эту страницу, это доказывает, что первый шаг сделанtest01.png

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);
    })

напиши в конце

  • Когда вы это видите, во-первых, вы очень настойчивый человек.В этой статье мало иллюстраций, и в основном это работа.Если вы прочитали ее от начала до конца, поставьте себе лайк.
  • В этой статье в основном рассказывается о том, зачем нужно шифрование и как шифровать
  • Вышеупомянутое 🌰 в основном для того, чтобы вы начали
  • Приветствую всех желающих прокомментировать проблему шифрования