Vue前端开发工程师如何与后端进行安全加密通信

887 阅读3分钟

首先是插件选择,需要前后端解密思路一致 :

前端用单向密钥加密--后端用单向密钥解密 后端用双向密钥加密--前端用双向密钥解密

1. 思路讲解:

微信图片_20220312210352.jpg

1.1 单向加密的作用:

对对称加密的密钥串进行加密处理,对传递后端的数据进行加密处理

1.2 对称密钥的作用:

对数据加密后传递后端,保持传递和渲染的时候数据不一致

1.3 方式如下:

  1. 前端生成对称加密密钥串(此时前端存储了对称解密密钥)
  2. 然后用单向加密对对称加密密钥串进行加密(用公钥加密的对密钥)
  3. 携带好生成的加密密钥串传给后台(后台进行私钥密钥串解析成对称密钥)
  4. 前端使用单向加密方法,加密数据后带给后端
  5. 后端进行单向解数据和双向密钥后,后端再使用双向密钥串进行加密传给前端
  6. 前端用双向解密解密,pass

1.4 选用加密插件版本:

"encryptlong": "^3.1.4",
"jsencrypt": "^3.2.1",
"crypto-js": "^4.1.1",

配置与使用加密插件:

一:配置文件 rsa.js

/* 产引入jsencrypt实现数据RSA加密 */
import JSEncrypt from 'jsencrypt' // 处理长文本数据时报错 jsencrypt.js Message too long for RSA
/* 产引入encryptlong实现数据RSA加密 */
import Encrypt from 'encryptlong' // encryptlong是基于jsencrypt扩展的长文本分段加解密功能。

// 存储加密公钥密钥串 
const publicKey = `12d5a6d4as65d1as23d1a3d4as5d64a3d21a3d245f4dsv1gfd3h15ut6i1y21jugh3km1i56uo1`

export default {
  /* JSEncrypt加密 */
  rsaPublicData(data) {
    var jsencrypt = new JSEncrypt()
    jsencrypt.setPublicKey(publicKey)
    // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
    var result = jsencrypt.encrypt(data)
    return result
  },
  /* JSEncrypt解密 */
  rsaPrivateData(data) {
    var jsencrypt = new JSEncrypt()
    jsencrypt.setPrivateKey(publicKey)
    // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
    var result = jsencrypt.encrypt(data)
    return result
  },
  /* 加密 */
  encrypt(data) {
    var encryptor = new Encrypt()
    encryptor.setPublicKey(publicKey)
    // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
    const result = encryptor.encryptLong(data)
    return result
  },
  /* 解密 - PRIVATE_KEY - 验证 */
  decrypt(data) {
    var encryptor = new Encrypt()
    encryptor.setPrivateKey(publicKey)
    // 如果是对象/数组的话,需要先JSON.stringify转换成字符串
    var result = encryptor.decryptLong(data)
    return result
  }
}

二: 配置aes.js

import CryptoJS from "crypto-js";

/**
 * CryptoJS AES 加密。str 是需要加密的字符串明文;key 是密钥;iv 是偏移向量,默认 iv 是 16 个 0(这个称为初始化向量),我们可以指定 iv 来进行加解密,加大破解难度;返回值为加密结果字符串密文
 *
 * @param {String} str
 * @param {String} key
 * @param {String} iv
 * @return {String}
 */
const key = getKey(16)
function aesEncrypt(str) {
  const formatedKey = CryptoJS.enc.Utf8.parse(key) // 将 key 转为 128bit 格式
  const encrypted = CryptoJS.AES.encrypt(str, formatedKey, { mode: CryptoJS.mode.ECB }) // 加密,使用CryptoJS的ECB加密方式进行密钥加密
  return encrypted.toString() // AES 加密生成的密文是一个对象,如果直接将其转为字符串是一个 Base64 编码串,在 encrypted.ciphertext 上的属性转为字符串才是后端需要的密文格式
}
/**
 * CryptoJS AES 解密。encryptedStr 字符串密文;key 是密钥;iv 是偏移量;返回结果为解密后的结果明文
 * 注意:key 与 iv 要与上面加密使用的 key 与 iv 保持一致
 *
 * @param {String} encryptedStr
 * @param {String} key
 * @param {String} iv
 * @return {String}
 */
function aesDecrypt(encryptedStr, dummy) {
  // const encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedStr) // 把密文由 128 bit 转为十六进制
  // const encryptedBase64Str = CryptoJS.enc.Base64.stringify(encryptedHexStr) // 再转为 Base64 编码的字符串
  const formatedKey = CryptoJS.enc.Utf8.parse(dummy || key) // 将 key 转为 128bit 格式
  const decryptedData = CryptoJS.AES.decrypt(encryptedStr, formatedKey, { mode: CryptoJS.mode.ECB }) // 解密
  return decryptedData.toString(CryptoJS.enc.Utf8) // 经过 AES 解密后,依然是一个对象,将其变成明文就需要按照 Utf8 格式转为字符串
}
/**
 * 生成密钥
 * @param n 生成多少位的密钥(默认8位)
 */
function getKey(n) {
  let chars = [
    "0",
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "A",
    "B",
    "C",
    "D",
    "E",
    "F",
    "G",
    "H",
    "I",
    "J",
    "K",
    "L",
    "M",
    "N",
    "O",
    "P",
    "Q",
    "R",
    "S",
    "T",
    "U",
    "V",
    "W",
    "X",
    "Y",
    "Z",
  ];
  if (n == null) {
    n = 8;
  }
  let res = "";
  for (let i = 0; i < n; i++) {
    let id = Math.ceil(Math.random() * 35);
    res += chars[id];
  }
  return res;
}

export default {
  key,
  aesDecrypt,
  aesEncrypt,
};

三:组件使用方法

import AES from "@/utils/aes.js"
import RSA from "@/utils/rsa.js"

// 加密的数据操作
    request.phoneNumber = RSA.encrypt(this.InformationList.phonenumber)
    request.email = RSA.encrypt(this.InformationList.Email)

// 接口传输:我们将生成的双向密钥加密传发送给后端,携带在formdata中
    await this.$http.getparams({ ...this.form,dummy: RSA.encrypt(AES.key) }).then()


// 展示解密数据
    phonenumber:AES.aesDecrypt(data.phoneNumbe, this.dummy),
    email:!res.email ? "" :AES.aesDecrypt(data.email, this.dummy)