玩命加载中🤣🤣🤣

前后端api交互安全


demo1

sequenceDiagram
	actor c as 客户端
	participant f as 前端服务器
	participant b as 后端服务器
	c ->> f: 触发请求
	f ->> +b: 发送请求
	b ->> b: 通过RSA生成pubkey1和prikey1
	note right of b: pubkey1, prikey1
	b -->> -f: 将pubkey1返回前端
	b --> +f: 
	f ->> f: 通过RSA生成pubkey2和prikey2
	note left of f: pubkey2, prikey2
	f ->> f: 加密: pubkey1(pubkey2) => secret1
	f ->> -b: 用secret1请求后端
	f --> +b: 
	b ->> b: 解密: prikey1(secret1) => pubkey2
	b ->> b: 加密: pubkey2(AESkey) => secret2
	b ->> -f: 返回secret2
	b --> +f: 
	f ->> f: 解密: prikey2(secret2) => AESkey
	f ->> f: 加密: AESkey(data) => secretData
	f ->> -b: 将加密数据发送给后端
<template>
  <div>
    <input type="text" v-model="text" />
    <button @click="encryptData">加密</button>
    <button @click="decryptData">解密</button>
  </div>
</template>

<script>
import CryptoJS from 'crypto-js'

export default {
  data() {
    return {
      text: '',
      key: null,
      nonce: null,
      ciphertext: null,
      tag: null
    }
  },
  methods: {
    // 使用AES算法加密数据
    encryptData() {
      const key = CryptoJS.lib.WordArray.random(16)
      const nonce = CryptoJS.lib.WordArray.random(12)
      const encrypted = CryptoJS.AES.encrypt(this.text, key, {
        mode: CryptoJS.mode.GCM,
        iv: nonce
      })
      this.key = CryptoJS.enc.Base64.stringify(key)
      this.nonce = CryptoJS.enc.Base64.stringify(nonce)
      this.ciphertext = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
      this.tag = CryptoJS.enc.Base64.stringify(encrypted.finalize())
    },
    // 使用AES算法解密数据
    decryptData() {
      const key = CryptoJS.enc.Base64.parse(this.key)
      const nonce = CryptoJS.enc.Base64.parse(this.nonce)
      const ciphertext = CryptoJS.enc.Base64.parse(this.ciphertext)
      const tag = CryptoJS.enc.Base64.parse(this.tag)
      const decrypted = CryptoJS.AES.decrypt(
        { ciphertext },
        key,
        {
          mode: CryptoJS.mode.GCM,
          iv: nonce,
          tag: tag
        }
      )
      this.text = decrypted.toString(CryptoJS.enc.Utf8)
    }
  }
}
</script>
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;

public class EncryptionUtil {
    private static final int KEY_SIZE = 2048;

    // 生成RSA密钥对
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
        generator.initialize(KEY_SIZE);
        return generator.generateKeyPair();
    }

    // 使用RSA公钥加密AES密钥
    public static byte[] encryptKey(byte[] key, PublicKey publicKey) throws Exception {
        byte[] encryptedKey = null;
        try {
            GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
            KeyParameter keyParameter = new KeyParameter(key);
            AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
            cipher.init(true, parameters);
            encryptedKey = new byte[cipher.getOutputSize(key.length)];
            int len = cipher.processBytes(key, 0, key.length, encryptedKey, 0);
            cipher.doFinal(encryptedKey, len);
        } catch (InvalidCipherTextException e) {
            e.printStackTrace();
        }

        return PublicKeyFactory.createKey(publicKey.getEncoded()).encrypt(encryptedKey);
    }

    // 使用RSA私钥解密AES密钥
    public static byte[] decryptKey(byte[] encryptedKey, PrivateKey privateKey) throws Exception {
        byte[] decryptedKey = PrivateKeyFactory.createKey(privateKey.getEncoded()).decrypt(encryptedKey);
        GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        KeyParameter keyParameter = new KeyParameter(decryptedKey);
        AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
        cipher.init(false, parameters);
        byte[] key = new byte[cipher.getOutputSize(decryptedKey.length)];
        int len = cipher.processBytes(decryptedKey, 0, decryptedKey.length, key, 0);
        cipher.doFinal(key, len);

        return key;
    }

    // 使用AES算法加密数据
    public static byte[] encryptData(byte[] data, byte[] key) throws Exception {
        GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        KeyParameter keyParameter = new KeyParameter(key);
        AEADParameters parameters = new AEADParameters(keyParameter, 128, new byte[12]);
        cipher.init(true, parameters);
        byte[] ciphertext = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, ciphertext, 0);
        cipher.doFinal(ciphertext, len);

        return ciphertext;
    }

    // 使用AES算法解密数据
    public static byte[] decryptData(byte[] ciphertext, byte[] key, byte[] nonce, byte[] tag) throws Exception {
        GCMBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        KeyParameter keyParameter = new KeyParameter(key);
        AEADParameters parameters = new AEADParameters(keyParameter, 128, nonce, tag);
        cipher.init(false, parameters);
        byte[] data = new byte[cipher.getOutputSize(ciphertext.length)];
        int len = cipher.processBytes(ciphertext, 0, ciphertext.length, data, 0);
        cipher.doFinal(data, len);

        return data;
    }

    public static void main(String[] args) throws Exception {
        // 生成RSA密钥对
        KeyPair keyPair = generateKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();

        // 加密数据
        String data = "Hello World!";
        byte[] key = new byte[16];
        for (int i = 0; i < key.length; i++) {
            key[i] = (byte) (Math.random() * 256);
        }
        byte[] encryptedKey = encryptKey(key, publicKey);
        byte[] nonce = new byte[12];
        for (int i = 0; i < nonce.length; i++) {
            nonce[i] = (byte) (Math.random() * 256);
        }
        byte[] ciphertext = encryptData(data.getBytes(StandardCharsets.UTF_8), key);
        byte[] tag = new byte[16];
        System.arraycopy(ciphertext, ciphertext.length - 16, tag, 0, 16);

        // 输出加密后的数据
        System.out.println("Key: " + Base64.getEncoder().encodeToString(key));
        System.out.println("Nonce: " + Base64.getEncoder().encodeToString(nonce));
        System.out.println("Ciphertext: " + Base64.getEncoder().encodeToString(ciphertext));
        System.out.println("Tag: " + Base64.getEncoder().encodeToString(tag));

        // 解密数据
        key = decryptKey(encryptedKey, privateKey);
        byte[] plaintext = decryptData(ciphertext, key, nonce, tag);
        System.out.println(new String(plaintext, StandardCharsets.UTF_8));  // 输出:Hello World!
    }
}

上述代码使用了CryptoJS库和Bouncy Castle库实现了前后端数据加密。在这个示例中,前端使用AES算法对数据进行加密,然后使用RSA公钥加密AES密钥,将加密后的密钥和加密后的数据一起发送给后端。后端使用RSA私钥解密AES密钥,然后使用解密后的密钥对数据进行解密。同样,后端也可以使用AES算法对数据进行加密,然后使用RSA公钥加密AES密钥,将加密后的密钥和加密后的数据一起发送给前端。前端使用RSA私钥解密AES密钥,然后使用解密后的密钥对数据进行解密。

demo2

sequenceDiagram
	actor a as 用户
	participant f as 前端服务器
	participant b as 后端服务器
	a ->> +f: 触发操作
	f ->> f: 生成随机AES密钥
	f ->> f: AES(data) => secretData
	f ->> f: RSA_priKey(AES) => aesKey
	f ->> +b: aesKey + secretData
	b ->> b: RSA_pubKey(aesKey) => AES
	b ->> b: AES(secretData) => data
	b ->> b: 同等方式加密
	b -->> -f: 响应数据
	f -->> -a: 响应给用户

文章作者: 👑Dee👑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 👑Dee👑 !
  目录