Node如何實作資料傳輸加密解密?以下這篇文章跟大家介紹一下Node.js實作前後端資料傳輸加密解密的方法,希望對大家有幫助!
node.js極速入門課程:進入學習
在前後端通訊過程中,一些敏感訊息,特別是用戶的帳號密碼,需要加密進行傳輸,如何選擇加密方式也是一門學問,這裡倒也不過多偏題了。 通常來說B/S架構中用的比較多的傳輸資料加密是RSA加密,核心思想就是公鑰加密,私鑰解密。 公鑰,可以理解為可以公開的鑰匙,伺服器將公鑰發給客戶端,客戶端用公鑰對資料進行加密傳輸,伺服器收到客戶端傳來的密文,再用自己的配對的私鑰進行解密,即可取得原始的資料。
大致流程如下圖所示:
Nodejs中有一個核心模組- crypto
提供各種加密、解密相關API。以下範例是基於[email protected]
版本進行編寫。
const crypto = require('crypto'); /** * 產生RSA公私鑰對 * @return {*} publicKey: 公鑰;privateKey: 私鑰 */ function genRSAKeyPaire() { const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'pkcs1', format: 'pem', }, privateKeyEncoding: { type: 'pkcs1', format: 'pem', }, }); return { publicKey, privateKey }; } // 列印產生的公私鑰對console.log(genRSAKeyPaire());
輸出範例如下:
(範例公私鑰已被刪除了一部分,請勿用於實驗)
{ publicKey: '-----BEGIN RSA PUBLIC KEY-----n' + 'MIICCgKCAgEAsitohTu9Jf2h+NPV4tNfFhPrlbStzXNM8wSEcskwtpwi6aZfgQC7n' + '/A7M1hN8Zk8WgiZjy05AHinWPvXo70OWj8TminIAjB2wh0nDqm+IQqN7r20uzeJmn' + 'GBf1KusGemChEiFwiad1h/OB9z9LC8zMYR/G+XAbFfcv8MxAMI9mgmS8t5+xeYm6n' + 'EMiCQkQjfqpErhW3oESj8hrdJdOZbiK3l0TgYLyjZRQu6pHzFkmd9We3BY1qcXo1n' + '2BtNKvqoH9QDJItsb3S9v2mOGl1rbItKlDrqYCdGY4iyXVIfagNWHraVzHqH/tern' + 'X+hOmLOwu+Npkz+oEDmnUq1UGY181PBGiNwHVodXx+DF5ckj/bGIxFG2nSiNe3dOn' + 'WLxV3+W8Af0006Oe+fRo1D7xt5SK5AipCpylKKYdyuP3MJ5dpPu7GMIcwj20Ndnun' + 'cDJJ2HH9kZAKz6/r62S7ALluFSecuZr0Dqc6SrJs43zBTpS/hSI33r01ste6Zel8n' + 'uRZKW/4FhUg8gW1KCM+Mp1MaZufOurCDc1Iec0SI71Tteg52BTpfb8cQ9Z1h0xWRn' + 'FdbmLMLuJkIi5oG2+FLAqlGknik0AxXpnlivSOW5Q+eLOh0DjQxxU2sCAwEAAQ==n' + '-----END RSA PUBLIC KEY-----n', privateKey: '-----BEGIN RSA PRIVATE KEY-----n' + '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' + '-----END RSA PRIVATE KEY-----n' }
2、公鑰加密
在有了公私鑰對的基礎上,使用公鑰進行加密,範例程式碼如下:
const crypto = require('crypto'); /** * 產生公私鑰對 * @return {*} publicKey: 公鑰;privateKey: 私鑰 */ function genRSAKeyPaire() { const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'pkcs1', format: 'pem', }, privateKeyEncoding: { type: 'pkcs1', format: 'pem', }, }); return { publicKey, privateKey }; } const { publicKey } = genRSAKeyPaire(); /** * 使用公鑰進行加密 * @param {String} data * @param {String} publicKey * @return {String} 加密後的密文 */ function publicKeyEncrypt(data, publicKey) { return crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64') } const entry = { 名稱: 'zhangsan', password: '123456' }; // 將資料轉為字串格式,並進行公鑰加密後列印console.log(publicKeyEncrypt(JSON.stringify(entry), publicKey));
輸出內容為以下格式:
(資料已做刪改)
Ri0p8QFmnYe8Xo36DextK242o9pcdL0QFDo6gUxhzjwQD30UFlqJL57na445BebSp1VT1z94emJgrME7xTDzV1tshtmVNtarqCUCzZMF4uYA1z94emJgrME7xTDzV1tshtmVNtarqCUCzZMF4uYAtZCQJMJhJw EWYNirPK6zEBw1e2V2jWoL+63+iGNyhtKFJI1ECGyMmXUWCMicUmgE/JiHJD7YXPKB9+WaB7Wgglj5udBdd4fALUp7qIo8TWJZJJkVMbeM IblSSy3Urle1AYsOFUzh9wV/H+uD+UNdaCvlvfmdV8hTIjjLNy9r/GbuaI5N0TkaX/dk47iUuorZabPoINEnM8lYxcKPvgVJufMfSX5wLxgx60IntLxgx2
3.私鑰解密
有了公鑰加密後的密文,再用私鑰解密,程式碼如下:
const crypto = require('crypto'); /** * 產生公私鑰對 * @return {*} publicKey: 公鑰;privateKey: 私鑰 */ function genRSAKeyPaire() { const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'pkcs1', format: 'pem', }, privateKeyEncoding: { type: 'pkcs1', format: 'pem', }, }); return { publicKey, privateKey }; } const { publicKey, privateKey } = genRSAKeyPaire(); /** * 使用公鑰進行加密 * @param {String} data * @param {String} publicKey * @return {String} 加密後的密文 */ function publicKeyEncrypt(data, publicKey) { return crypto.publicEncrypt(publicKey, Buffer.from(data)).toString('base64') } const entry = { 名稱: 'zhangsan', password: '123456' }; const encryptedData = publicKeyEncrypt(JSON.stringify(entry), publicKey); /** * 使用私鑰進行解密 * @param {String} encryptedData * @param {String} privateKey * @return {String} 解密後的明文 */ function privateKeyDecrypt(encryptedData, privateKey) { return crypto.privateDecrypt(privateKey, Buffer.from(encryptedData, 'base64')).toString(); } const originData = privateKeyDecrypt(encryptedData, privateKey); // 列印用私鑰解密後的資料console.log(originData);
輸出結果:
{"name":"zhangsan","password":"123456"}
和我們上面定義的entry
資料內容一致,說明解密成功,但是解密後是一個字串,如果原始資料是一個物件的話,別忘記了將其反序列化為物件。
在日常開發中,涉及到前後端通信,特別是重要的信息,為了防止被第三方獲取從而加以利用,一般都會做一下通信傳輸加密,最基本的就是使用https
協議,但是光有https協議還不夠(容易被中間人劫持攻擊)。 因此要對資料在應用層進行加密以防止資料被他人劫持利用,使用非對稱加密可以保證發送的密文只有擁有私鑰的伺服器才能解開,從而避免密文被其餘無關人員解密並加以利用。 網路領域沒有絕對的安全,只有不斷提升自己的安全意識,增強自己的安全技能,才是長久之計。