最近在作一個node項目,須要對前端傳遞給node端的敏感數據進行加密,並在node端對該加密數據進行解密;由於在作node項目以前,與後端配合開發過相似的需求,即前端加密後端解密;因此就嘗試採用RSA非對稱加密算法來實現。因爲第一次採用RSA來完成加解密的整個過程,遇到了很多坑;不過因爲種種緣由,最後採用了AES的加密方式;下面就來講說前端加解密實現方案。javascript
固然首先想到採用的加解密算法就是RSA
,其關鍵在於算法的公鑰/祕鑰
。其主要用法:php
因而,基於RSA算法來實現加解密,找到了對應的瀏覽器端庫jsencrypt
和node端的庫node-rsa
來實現具體的功能。前端
具體實現思路:java
使用jsencrypt在前端實現用公玥加密,使用node-rsa在node端用私鑰解密。node
因爲採用的是RSA算法,因此須要先後端約定具體的公鑰和私鑰。怎麼生存公鑰私鑰呢?laravel
因而根據jsencrypt
庫的介紹,使用openssl
方式來生成對應的公鑰和私鑰。因而生成的公鑰和私鑰大概是以下樣子:git
// 私鑰 -----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-----
// 公鑰 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtN FOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76 xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/ZKBUSLKL7eibMxZtMlUDHjm4 gwQco1KRMDSmXSMkDwIDAQAB -----END PUBLIC KEY-----
因而,使用生成的公鑰,前端使用jsencrypt
提供的加密api來對敏感數據加密github
var publickey = `-----BEGIN PUBLIC KEY----- xxxxxx -----END PUBLIC KEY-----`; var encrypt = new JSEncrypt(); encrypt.setPublicKey(publickey); var encryptdata = encrypt.encrypt(data);
node端使用node-rsa
來完成解密:web
const privatekey = `-----BEGIN RSA PRIVATE KEY----- xxxx -----END RSA PRIVATE KEY-----` const rsa = new NodeRSA(privatekey, 'pkcs8-private-pem', {encryptionScheme: 'pkcs1'}); const decryptdata = rsa.decrypt(data, 'utf8');
執行到這裏,node-rsa一直報下面的錯誤:算法
Error: Error during decryption (probably incorrect key). Original error: Error: Incorrect data or key
意思就是對應的解密私鑰不正確,查看node-rsa
有關公鑰私鑰,他是有規定的,具體以下:
能夠看出,node-rsa的公鑰私鑰的起始字符串有如下兩種:
pkcs1: 公鑰(-----BEGIN RSA PUBLIC KEY-----)和私鑰(-----BEGIN RSA PRIVATE KEY-----)
pkcs8: 公鑰(-----BEGIN PUBLIC KEY-----) 和 私鑰 (-----BEGIN PRIVATE KEY-----)
無論node-rsa規定的那種私鑰scheme,都與咱們以前使用openssl
生成的私鑰字符串的開始結束字符不一樣,致使node-rsa認不出對應的私鑰。
那麼,咱們是否能夠對openssl生成的私鑰的起始字符串按照node-rsa進行修改呢,咱們簡單試一下,結果產生以下錯誤:
InvalidAsn1Error: Expected 0x30: got 0x2
因此,既然不能按照openssl生成的公鑰私鑰方式,那麼可否有其餘方式來生成呢?經過google發現,能夠經過node-rsa
的相關api來生成對應的公鑰私鑰,而且jsencrypt
庫也能夠經過其生成的公鑰來解密。node-rsa對應生成公鑰私鑰以下:
//1.建立RSA對象,並指定 祕鑰長度 var key = new NodeRSA({ b: 512 }); key.setOptions({ encryptionScheme: 'pkcs1' });//指定加密格式 //2.生成 公鑰私鑰,使用 pkcs8標準,pem格式 var publicPem = key.exportKey('pkcs8-public-pem');//制定輸出格式 var privatePem = key.exportKey('pkcs8-private-pem'); console.log(pkcsType+'公鑰:\n',publicPem); console.log(pkcsType+'私鑰:\n', privatePem);
這樣,經過生成的公鑰,前端使用jsencrypt庫來加密,node端使用node-rsa根據私鑰來解密,解決了以前遇到問題。
在使用RSA加密算法前,使用過前端加密庫crypto-js
來完成加解密,由於:
它算是比較成熟且github star數也比較多,使用起來比較放心。
crypto-js也提供了多種加密算法,惟獨不包含RSA加密算法。
該庫是先後端通用的庫,避免引入多個庫
基於此緣由,選用了crypto-js提供的AES加密算法來完成需求。
具體的實現方式以下
具體代碼以下:
import CryptoJS from 'crypto-js'; const AES_KEY = "qq3217834abcdefg"; //16位 const AES_IV = "1234567890123456"; //16位 function aes_encrypt(plainText) { var encrypted = CryptoJS.AES.encrypt(plainText, CryptoJS.enc.Utf8.parse(AES_KEY), {iv: CryptoJS.enc.Utf8.parse(AES_IV)}); return CryptoJS.enc.Base64.stringify(encrypted.ciphertext); } data = 'my message'; encrypt_data = aes_encrypt(data); console.log(encrypt_data);
key
和iv
來解密對應的node端代碼以下:
function aes_decrypt(ciphertext) { var decrypted = CryptoJS.AES.decrypt(ciphertext, CryptoJS.enc.Utf8.parse(AES_KEY), {iv: CryptoJS.enc.Utf8.parse(AES_IV)}); return decrypted.toString(CryptoJS.enc.Utf8); } const encrypt_data = ctx.cookie('data'); cibst decrypt_data = aes_decrypt(encrypt_data); console.log(decrypt_data);
至此,先後端加解密就大功告成了。
上面兩種方式都能實現先後端的加密解密,就其安全性而言存在差異,具體能夠參考以下對比表格:
加密算法 | 實現方式 | 安全性 |
---|---|---|
RSA | 先後端約定統一的公鑰私鑰,前端用暴露的公鑰加密,私鑰存在後server端 | 私鑰存在server端,即便暴露公鑰;加密是安全的 |
AES | 前端後端都使用一樣的key(或者還有iv)來進行加解密,key同時暴露在先後端 | 因爲後端使用一樣的key來解密,因爲前端暴露了key,加密不安全 |
對於AES這種將加密key暴露在前端,不夠安全;可是前端加密是防不了小人的,若是真要防,能夠將加密算法的js文件進行壓縮加密,不斷更新的手段來使js文件難以獲取,讓攻擊者難以獲取加密算法來防止。
一、jsencrypt
二、PHP 和 Web 端對稱加密傳輸|JSEncrypt|CryptoJS
三、node-rsa非對稱加密
四、js 前端 AES 及 RSA 加解密