前言
就前後端分離的開發方式而言,我們以接口爲標準來進行推動,定義好接口,各自開發自己的功能,最後進行聯調整合。前後端的傳輸通過HTTP進行傳輸,也帶來了一些安全問題,如果抓包、模擬請求、洪水攻擊、參數劫持、網絡爬蟲等都能夠獲取請求的數據包。那麼如何對數據進行保護呢?
可以提升網絡安全的方式
-
採用HTTPS協議
-
密鑰存儲到服務端而非客戶端,客戶端應從服務端動態獲取密鑰
-
請求隱私接口,利用token機制校驗其合法性
-
對請求參數進行合法性校驗
-
對請求參數進行簽名認證,防止參數被篡改
-
對輸入輸出參數進行加密,客戶端加密輸入參數,服務端加密輸出參數
HTTP VS HTTPS
普通的HTTP協議是以明文形式進行傳輸,不提供任何方式的數據加密,很容易解讀傳輸報文。而HTTPS協議在HTTP基礎上加入了SSL層,而SSL層通過證書來驗證服務器的身份,併爲瀏覽器和服務器之間的通信加密,保護了傳輸過程中的數據安全。
Aes數據加密實現方式
實現步驟:前端對數據進行加密,API對收到的數據進行解密。操作後,將數據在次加密並返回給前端,前端使用解密後的數據。
說明:Aes 中加密解密有多種模式,本文以base64爲例。
vue 中封裝的加密解密文件 ase.js
/***
* aes Base64 方式加密解密
*/
const CryptoJS = require('crypto-js'); //引用AES源碼js
const key = CryptoJS.enc.Utf8.parse("FFff123456.!-12ss"); //十六位十六進制數作爲密鑰
const iv = CryptoJS.enc.Utf8.parse('FFff123456.!-12ss'); //十六位十六進制數作爲密鑰偏移量
//解密方法
function Decrypt(word) {
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();
}
//加密方法
function Encrypt(word) {
let srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {iv: iv,mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.ZeroPadding});
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
export default {
Decrypt ,
Encrypt
}
API 中封裝的加密解密文件 Aes.java
package com.platform.util;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/***
* Aes Base64 加密和解密
* @author Zyh
*
*/
public class Aes {
//密鑰 (需要前端和後端保持一致)
private static final String KEY = "FFff123456.!-12ss";
private static final String IV = "FFff123456.!-12ss";
/**
* 加密方法
* @param data 要加密的數據
* @param key 加密key
* @param iv 加密iv
* @return 加密的結果
* @throws Exception
*/
public static String encrypt(String data, String key, String iv) throws Exception {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
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(iv.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;
}
}
/**
* 解密方法
* @param data 要解密的數據
* @param key 解密key
* @param iv 解密iv
* @return 解密的結果
* @throws Exception
*/
public static String desEncrypt(String data, String key, String iv) throws Exception {
try {
byte[] encrypted1 = new Base64().decode(data);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original);
return originalString;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用默認的key和iv加密
* @param data
* @return
* @throws Exception
*/
public static String encrypt(String data) throws Exception {
return encrypt(data, KEY, IV);
}
/**
* 使用默認的key和iv解密
* @param data
* @return
* @throws Exception
*/
public static String desEncrypt(String data) throws Exception {
return desEncrypt(data, KEY, IV);
}
}
至此,就可以進行前後端數據加密傳輸,這也僅僅是其中的一種解決方案,關於加解密的方法還有很多,感興趣的小夥伴們可以繼續做一些深入的研究哈~