【分布式安全】【加密】前端vue和后端java使用AES加密参数互相验证请求

需求背景

前端参数传至后端,需要加密参数,以防止被爆破和信息泄漏。又因为是暴露给外部使用的接口,无法使用oath2等内部权限

技术栈

前端使用vue开发。后端主要使用java开发。加密方案使用AES算法。 base64。

解决方案

前端vue解决方案

首先我们使用 crypto-js加密类库

1)安装

cnpm install crypto-js --save

此外使用淘宝的cnpm, 下载速度快。若没有安装淘宝此包。直接使用npm也是可以的
2) 写一个通用工具js

/**
 * AES工具类
 */
import CryptoJS from 'crypto-js'
const aeskey = "crm25sqdc58start";

const KEY = CryptoJS.enc.Utf8.parse("zhelixie16weimim"); //""中与后台一样  密码
const IV = CryptoJS.enc.Utf8.parse("zhelixie16weimim"); //""中与后台一样
export default { //加密
  encrypt(word) {
    let key = KEY
    let iv = IV
    let srcs = CryptoJS.enc.Utf8.parse(word);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, {
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.ZeroPadding
    });
    // console.log("-=-=-=-", encrypted.ciphertext)
    return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
  },
  //解密
  decrypt(word) {
    let key = KEY
    let iv = IV
    let base64 = CryptoJS.enc.Base64.parse(word);
    let src = CryptoJS.enc.Base64.stringify(base64);

    var decrypt = CryptoJS.AES.decrypt(src, key, {
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.ZeroPadding
    });

    var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
  }

}

 3)调用

import AesUtil from "@/utils/aes-util";

...

let encryLink = AesUtil.encrypt(this.userInfo.userId);

let deencryLink = AesUtil.decrypt(encryLink);

如果是放在url里的参数,还需要对整个uri encode或对参数encode,不然如果里面有加号等特殊符号,后端收到会出现问题。

this.link =
        this.link +
        "?param=" +
        encodeURIComponent(AesUtil.encrypt(this.userInfo.userId));

 后端Java解决方案

1)引入base64依赖


			commons-net
			commons-net
			3.0.1
		

2)写一个util类

 package com.bj58.crm.sqdc.util;  
  
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.net.util.Base64;  
  
  
/** 
 * AES工具类 
 * @author paymoon.com @不止鱼
 * 
 
 *   因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件。 
 *   替换的文件:%JDK_HOME%\jre\lib\security\local_policy.jar 
 * 参考: http://czj4451.iteye.com/blog/1986483 
 */  
public class AESUtil {  
    // 密钥  
    public static String key = "zhelixie16weimim";  
    private static String charset = "utf-8";  
    // 偏移量  
    private static int offset = 16;  
    private static String transformation = "AES/CBC/NoPadding";  
    private static String algorithm = "AES";  
  
    /** 
     * 加密 
     *  
     * @param content 
     * @return 
     */  
    public static String encrypt(String content) {  
        try {
			return encrypt(content, key);
		} catch (Exception e) {
		}
		return null;  
    }  
  
    /** 
     * 解密 
     *  
     * @param content 
     * @return 
     */  
    public static String decrypt(String content) {  
        return decrypt(content, key);  
    }  
  
    /** 
     * 加密 
     *  
     * @param content 
     *            需要加密的内容 
     * @param key 
     *            加密密码 
     * @return 
     */  
//    public static String encrypt(String content, String key) {  
//        try {  
//            SecretKeySpec skey = new SecretKeySpec(key.getBytes(Charset.forName("UTF-8")), algorithm);  
//            IvParameterSpec iv = new IvParameterSpec(key.getBytes(Charset.forName("UTF-8")), 0, offset);  
//            Cipher cipher = Cipher.getInstance(transformation);  
//            byte[] byteContent = content.getBytes(charset);  
//            cipher.init(Cipher.ENCRYPT_MODE, skey, iv);// 初始化  
//            byte[] result = cipher.doFinal(byteContent);  
//            return new Base64().encodeToString(result); // 加密  
//        } catch (Exception e) {  
//        }  
//        return null;  
//    }  
    public static String encrypt(String data, String key) throws Exception {
        try {

            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");//"算法/模式/补码方式"NoPadding PkcsPadding
            int blockSize = cipher.getBlockSize();

            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }

            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(key.getBytes());

            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);

            return new Base64().encodeToString(encrypted);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /** 
     * AES(256)解密 
     *  
     * @param content 
     *            待解密内容 
     * @param key 
     *            解密密钥 
     * @return 解密之后 
     * @throws Exception 
     */  
    public static String decrypt(String content, String key) {  
        try {  
  
            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);  
            IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);  
            Cipher cipher = Cipher.getInstance(transformation);  
            cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化  
            byte[] result = cipher.doFinal(new Base64().decode(content));  
            return new String(result); // 解密  
        } catch (Exception e) {  
        }  
        return null;  
    }  
  
    public static void main(String[] args) throws Exception {  
        String s = "65de2594-9ace-e211-915e-00155d607702";  
        // 加密  
        System.out.println("加密前:" + s);  
        String encryptResultStr = encrypt(s);  
        System.out.println("加密后:" + encryptResultStr);  
        // 解密  
        System.out.println("解密后:" + decrypt("CehzNznR6gQfgwahwUuoog=="));  
    }  
}  

3)方法调用直接参数main即可

加密注意的点

1、前后端相互校验,不同于单后端或前端加密。两端需要有共同的key配置。算法/模式/补码方式。

2、后端java加密的算法/模式/补码方式配置是 AES/CBC/NoPadding,偏移量使用的是key。则前端vue中,也要使用相同的偏移,以及模式CBC,补码使用CryptoJS.pad.ZeroPadding。

参考

vue 方案https://chris-wei.github.io/2018/04/13/Crypto-js/

java和vue使用AES加密验证前端请求 - qq_15070281的博客 - CSDN博客
https://blog.csdn.net/qq_15070281/article/details/83652159

你可能感兴趣的:(【分布式安全】【加密】前端vue和后端java使用AES加密参数互相验证请求)