node中的密碼安全(加密)
本文將講解對于前后端分離的項目,前端注冊或登錄時如何保證用戶密碼安全傳輸?shù)絪erver端,最終存入數(shù)據(jù)庫
為什么需要加密
加密真的有必要嗎?
我們先來看一看前端發(fā)起的ajax請求中,如果不對密碼進行加密,會發(fā)生什么。
f12打開chrome開發(fā)者工具,找到請求,查看請求參數(shù)如下:
如果你的協(xié)議是http,那么前端傳給后端的密碼差不多是裸奔狀態(tài),因為http傳輸?shù)氖敲魑?,很可能在傳輸過程中被竊聽,偽裝或篡改。
那么,弄個https不就好了嗎?
https的確能夠極大增加網(wǎng)站的安全性,但是用https得先買證書(也有免費的),對于個人站點或者不想弄證書的情況下,那最起碼也得對用戶密碼進行一下加密吧。
流程圖
先看一下大體流程圖,首先,我們用工具生成公鑰和私鑰,將其放入server端,前端發(fā)起請求獲取公鑰,拿到公鑰后對密碼進行加密,然后將加密后的密碼發(fā)送到server端,server端將用密鑰解密,最后再用sha1加密密碼,存入數(shù)據(jù)庫。
生成RSA公鑰和密鑰
既然選擇RSA加密,那么首先得有工具啊,常見的有openssl,但這里不介紹,感興趣的請自行查閱,對于node而言,我介紹一個不錯的庫Node-RSA,我們將用它來生成RSA公鑰和密鑰。
RSA是一種非對稱加密算法,即由一個密鑰
和一個公鑰
構(gòu)成的密鑰對,通過密鑰加密,公鑰解密,或者通過公鑰加密,密鑰解密。其中,公鑰可以公開,密鑰必須保密
。
用Node-RSA生成的公鑰和密鑰代碼如下:
const NodeRSA = require('node-rsa') const fs = require('fs') // Generate new 512bit-length key var key = new NodeRSA({b: 512}) key.setOptions({encryptionScheme: 'pkcs1'}) var privatePem = key.exportKey('pkcs1-private-pem') var publicDer = key.exportKey('pkcs8-public-der') var publicDerStr = publicDer.toString('base64') // 保存返回到前端的公鑰 fs.writeFile('./pem/public.pem', publicDerStr, (err) => { if (err) throw err console.log('公鑰已保存!') }) // 保存私鑰 fs.writeFile('./pem/private.pem', privatePem, (err) => { if (err) throw err console.log('私鑰已保存!') })
執(zhí)行完成后,我們將在根目錄下得到公鑰和私鑰文件:
注意:server端的公鑰和密鑰應(yīng)該隔一段時間換一次,比如每次服務(wù)器重啟時。
前端加密
核心代碼如下:
<script src="https://cdn.bootcss.com/jsencrypt/2.3.1/jsencrypt.min.js"></script> <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script> <script> function reg() { axios({ method: 'post', url: 'http://127.0.0.1:3000/getPublicKey' }) .then(res => { let result = res.data // 從后端獲取的公鑰 String var publicPem = result // 用JSEncrypt對密碼進行加密 var encrypt = new JSEncrypt() encrypt.setPublicKey(publicPem) var password = 'abc123' password = encrypt.encrypt(password) axios({ method: 'post', url: 'http://127.0.0.1:3000/reg', data: { password: password } }) .then(res => { let result = res.data console.log(result) }) .catch(error => { console.log(error) }) }) } </script>
前端將用到jsencrypt對其進行加密,詳細用法請參考github。
后端解密
后端核心代碼:
const express = require('express'); const crypto = require('crypto'); const fs = require('fs'); var privatePem = fs.readFileSync('./pem/private.pem'); var app = express(); app.use(express.json()); // CORS 注意:要放在處理路由前 function crossDomain(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); } app.use(crossDomain) app.use(function (req, res, next) { // 不加會報錯 if (req.method === 'OPTIONS') { res.end('ok') return } switch (req.url) { case '/getPublicKey': let publicPem = fs.readFileSync('./pem/public.pem', 'utf-8') res.json(publicPem) break case '/reg': // 解密 var privateKey = fs.readFileSync('./pem/private.pem', 'utf8') var password = req.body.password var buffer2 = Buffer.from(password, 'base64') var decrypted = crypto.privateDecrypt( { key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING // 注意這里的常量值要設(shè)置為RSA_PKCS1_PADDING }, buffer2 ) console.log(decrypted.toString('utf8')) // sha1加密 var sha1 = crypto.createHash('sha1'); var password = sha1.update(decrypted).digest('hex'); console.log('輸入到數(shù)據(jù)庫中的密碼是: ', password) // 存入數(shù)據(jù)庫中 // store to db... res.end('reg ok') break } }) app.listen(3000, '127.0.0.1')
這里,我是用node自帶模塊crpto進行解密,當然,你也可以用Node-RSA的方法進行解密。
最后
我們再來看一看前端請求的密碼信息:
這樣一串字符,即便被他人獲取,如果沒有密鑰,在一定程度上,他是無法知道你的密碼的。
當然,關(guān)于網(wǎng)絡(luò)安全是一個大話題,本篇只是對其中的一小部分進行介紹,歡迎留言討論,希望對您有幫助。,也希望大家多多支持腳本之家。
相關(guān)文章
Node.js + Redis Sorted Set實現(xiàn)任務(wù)隊列
本文給大家分享的是使用Node.js + Redis Sorted Set實現(xiàn)任務(wù)隊列的方法示例,非常的實用,有需要的小伙伴可以參考下2016-09-09快速掌握Node.js中setTimeout和setInterval的使用方法
這篇文章主要為大家介紹了快速掌握Node.js中setTimeout和setInterval的使用方法,感興趣的小伙伴們可以參考一下2016-03-03