SpringBoot整合資料傳輸加密
阿新 • • 發佈:2022-12-04
前言
近期在對開發框架安全策略方面進行升級優化,提供一些通用場景的解決方案,本文針對前後端資料傳輸加密進行簡單的分享,處理流程設計如下圖所示,本加密方法對原有專案相容性較好,只需要更換封裝好的加密Ajax請求方法,後端統一攔截判斷是否需要解密即可
生成DESKey
生成的DES加密金鑰一定是8的整數倍的位數
function getRandomStr() { let str = "" let array = [ "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", "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", ]; for (let i = 0; i < 8; i++) { str += array[Math.round(Math.random() * (array.length - 1))]; } return str; }
生成RSA金鑰對
RSA金鑰對有很多種格式,因為需要和前端演算法庫互聯互通,這裡選擇的是1024位,Padding方式為PKSC1
public static Map<String, String> createKeysPKSC1(int keySize) { // map裝載公鑰和私鑰 Map<String, String> keyPairMap = new HashMap<String, String>(); try { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); SecureRandom random = new SecureRandom(); KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC"); generator.initialize(keySize, random); KeyPair keyPair = generator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); String publicKeyStr = new String(Base64.encodeBase64(publicKey.getEncoded())); String privateKeyStr = new String(Base64.encodeBase64(privateKey.getEncoded())); keyPairMap.put("publicKey", publicKeyStr); keyPairMap.put("privateKey", privateKeyStr); } catch (Exception e) { e.printStackTrace(); } // 返回map return keyPairMap; }
前端DES加密
引入crypto.js第三方庫
function encryptByDES(message, key) { var keyHex = CryptoJS.enc.Utf8.parse(key); var encrypted = CryptoJS.DES.encrypt(message, keyHex, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); }
前端RSA加密
引入jsencrypt,js第三方庫
function encryptByRSA(data, publicKey) {
var encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey)
return encryptor.encrypt(data);;
}
後端RSA解密
public static String decryptPKSC1(String data, String privateKeyStr) {
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
RSAPrivateKey privateKey = getPrivateKeyPKSC1(privateKeyStr);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
} catch (Exception e) {
throw new RuntimeException("解密字串[" + data + "]時遇到異常", e);
}
}
後端DES解密
public static String decrypt(String data, String key) throws IOException,
Exception {
if (data == null)
return null;
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(data);
byte[] bt = decrypt(buf, key.getBytes("UTF-8"));
return new String(bt, "UTF-8");
}
後端自定義攔截器
public class XSSFilter implements Filter, Ordered {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String contentType = request.getContentType();
if (StringUtils.isNotBlank(contentType) && contentType.contains("application/json")) {
XSSBodyRequestWrapper xssBodyRequestWrapper = new XSSBodyRequestWrapper((HttpServletRequest) request);
chain.doFilter(xssBodyRequestWrapper, response);
} else {
chain.doFilter(request, response);
}
}
@Override
public int getOrder() {
return 9;
}
}
public class XSSBodyRequestWrapper extends HttpServletRequestWrapper {
private String body;
public XSSBodyRequestWrapper(HttpServletRequest request) {
super(request);
try{
body = XSSScriptUtil.handleString(CommonUtil.getBodyString(request));
String encrypt = request.getHeader("encrypt");
if (!StringUtil.isEmpty(encrypt)) {
String privateKey = RSAEncryptUtil.getSystemDefaultRSAPrivateKey();
String desEncryptStr = RSAEncryptUtil.decryptPKSC1(encrypt, privateKey);
JSONObject obj = JSONObject.parseObject(body);
String encryptParam = obj.getString("encryptParam");
body = DESEncryptUtil.decrypt(encryptParam, desEncryptStr);
}
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8")));
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
}