最近公司一個項目在傳輸數據的時候,測試部門安全掃描後,發現密碼類型的數據是明文傳輸的,果斷不符合要求,讓加密,就有了接下來的故事。html
先後端使用HTTP協議進行交互的時候,因爲HTTP報文爲明文,因此一般狀況下對於比較敏感的信息能夠經過加密在前端加密,而後在後端解密實現"混淆"的效果,避免在傳輸過程當中敏感信息的泄露(如,密碼,證件信息等)。不過前端加密只能保證傳輸過程當中信息是‘混淆’過的,對於高手來講,打個debugger,照樣能夠獲取到數據,並不安全,所謂的前端加密只是稍微增長了攻擊者的成本,並不能保證真正的安全。
綜上,服務端絕對不能相信前端傳遞過來的密文直接保存入庫,只能經過服務端本身加密進行加密保存。那麼前端加密是否是就沒有意義了呢?答案是否認的,至少能夠保證傳輸過程當中不是明文傳輸,若是先後端交互須要安全的通道建議使用HTTPS協議進行通訊。前端
簡單來講,加密分兩種方式git
對稱加密採用了對稱密碼編碼技術,它的特色是文件加密和解密使用相同的密鑰加密也就是密鑰也能夠用做解密密鑰,這種方法在密碼學中叫作對稱加密算法,對稱加密算法使用起來簡單快捷,密鑰較短,且破譯困難,除了數據加密標準(DES),另外一個對稱密鑰加密系統是國際數據加密算法(IDEA),它比DES的加密性好,並且對計算機功能要求也沒有那麼高
常見的對稱加密算法有DES、3DES、Blowfish、IDEA、RC四、RC五、RC6和AESgithub
**非對稱加密算法須要兩個密鑰:公鑰(publickey)和私鑰(privatekey)。 公鑰與私鑰是一對,若是用公鑰對數據進行加密,只有用對應的私鑰才能解密;若是用私鑰對數據進行加密,那麼只有用對應的公鑰才能解密。由於加密和解密使用的是兩個不一樣的密鑰,因此這種算法叫做非對稱加密算法。
非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把做爲公鑰向其它方公開;獲得該公鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;甲方再用本身保存的另外一把專用密鑰對加密後的信息進行解密。甲方只能用其專用密鑰解密由其公鑰加密後的任何信息。**
常見的非對稱加密算法有:RSA、ECC(移動設備用)、Diffie-Hellman、El Gamal、DSA(數字簽名用)算法
(1)使用Crypto-JS經過DES算法在前端加密npm
npm install crypto-js
(2)加解密
使用DES算法,工做方式爲ECB,填充方式爲PKcs7後端
var CryptoJS = require("crypto-js"); const secretKey = 'com.sevenlin.foo.key'; var afterEncrypt = CryptoJS.DES.encrypt('encryptCode', CryptoJS.enc.Utf8.parse(secretKey), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).toString() console.log(afterEncrypt);//8/nZ2vZXxOzPhU7ZHBwz7w== var afterDecrypt = CryptoJS.DES.decrypt(afterEncrypt, CryptoJS.enc.Utf8.parse(secretKey), { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); console.log(afterDecrypt);//encryptCode
(3)使用BC經過DES算法在後端解密
a.安裝安全
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency>
b.加解密工具ide
public class DesCipherUtil { private DesCipherUtil() { throw new AssertionError("No DesCipherUtil instances for you!"); } static { // add BC provider Security.addProvider(new BouncyCastleProvider()); } /** * 加密 * * @param encryptText 須要加密的信息 * @param key 加密密鑰 * @return 加密後Base64編碼的字符串 */ public static String encrypt(String encryptText, String key) { if (encryptText == null || key == null) { throw new IllegalArgumentException("encryptText or key must not be null"); } try { DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec); Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] bytes = cipher.doFinal(encryptText.getBytes(Charset.forName("UTF-8"))); return Base64.getEncoder().encodeToString(bytes); } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) { throw new RuntimeException("encrypt failed", e); } } /** * 解密 * * @param decryptText 須要解密的信息 * @param key 解密密鑰,通過Base64編碼 * @return 解密後的字符串 */ public static String decrypt(String decryptText, String key) { if (decryptText == null || key == null) { throw new IllegalArgumentException("decryptText or key must not be null"); } try { DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = secretKeyFactory.generateSecret(desKeySpec); Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC"); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(decryptText)); return new String(bytes, Charset.forName("UTF-8")); } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | NoSuchPaddingException | BadPaddingException | NoSuchProviderException | IllegalBlockSizeException e) { throw new RuntimeException("decrypt failed", e); } } }
c.解密前端的加密信息工具
String fromWeb = "8/nZ2vZXxOzPhU7ZHBwz7w=="; String key = "com.sevenlin.foo.key"; String afterDecrypt = DesCipherUtil.decrypt(fromWeb, key); System.out.println(afterDecrypt);//encryptCode
(1)下載加密文件依賴
(2) 引入依賴
<script src="bin/jsencrypt.min.js"></script>
或者
import '../../assets/js/jsencrypt.min.js';
(3)使用方式
this.privateKey=`-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQ WMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNR aY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4gwQco1KRMDSmXSMkDwIDAQAB AoGAfY9LpnuWK5Bs50UVep5c93SJdUi82u7yMx4iHFMc/Z2hfenfYEzu+57fI4fv xTQ//5DbzRR/XKb8ulNv6+CHyPF31xk7YOBfkGI8qjLoq06V+FyBfDSwL8KbLyeH m7KUZnLNQbk8yGLzB3iYKkRHlmUanQGaNMIJziWOkN+N9dECQQD0ONYRNZeuM8zd 8XJTSdcIX4a3gy3GGCJxOzv16XHxD03GW6UNLmfPwenKu+cdrQeaqEixrCejXdAF z/7+BSMpAkEA8EaSOeP5Xr3ZrbiKzi6TGMwHMvC7HdJxaBJbVRfApFrE0/mPwmP5 rN7QwjrMY+0+AbXcm8mRQyQ1+IGEembsdwJBAN6az8Rv7QnD/YBvi52POIlRSSIM V7SwWvSK4WSMnGb1ZBbhgdg57DXaspcwHsFV7hByQ5BvMtIduHcT14ECfcECQATe aTgjFnqE/lQ22Rk0eGaYO80cc643BXVGafNfd9fcvwBMnk0iGX0XRsOozVt5Azil psLBYuApa66NcVHJpCECQQDTjI2AQhFc1yRnCU/YgDnSpJVm1nASoRUnU8Jfm3Oz uku7JUXcVpt08DFSceCEX9unCuMcT72rAQlLpdZir876 -----END RSA PRIVATE KEY-----`; this.publicKye=`-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76 xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4 gwQco1KRMDSmXSMkDwIDAQAB -----END PUBLIC KEY-----`; var encrypt = new JSEncrypt(); encrypt.setPublicKey(this.publicKye); var encrypted = encrypt.encrypt('encryptCode');//w1a1FXmlbFj9yOxLCoqIzNo2ytXypyupZABsi/e4kMA9mERngmaDwlOuHsUDQKC0nK1v7Ehr3vYKcALFQvjscWEkGIW/UWCk73jArwqEYF1wd45eHSCPwUeB85Ellr+IYTqhZXcfmHZUCuprF2gayPUecq7F51aWxpfqMP0uvtY= // Decrypt with the private key... var decrypt = new JSEncrypt(); decrypt.setPrivateKey(this.privateKey); var uncrypted = decrypt.decrypt(encrypted);//encryptCode
生成publickey和privateKey的在線地址
雖然前端能夠加密,終歸不是安全方式,若是爲了更加的安全仍是使用https傳輸,後端加密保存吧!