node中的密碼安全(加密)
本文將講解對(duì)于前后端分離的項(xiàng)目,前端注冊(cè)或登錄時(shí)如何保證用戶密碼安全傳輸?shù)絪erver端,最終存入數(shù)據(jù)庫(kù)
為什么需要加密
加密真的有必要嗎?
我們先來(lái)看一看前端發(fā)起的ajax請(qǐng)求中,如果不對(duì)密碼進(jìn)行加密,會(huì)發(fā)生什么。
f12打開(kāi)chrome開(kāi)發(fā)者工具,找到請(qǐng)求,查看請(qǐng)求參數(shù)如下:

如果你的協(xié)議是http,那么前端傳給后端的密碼差不多是裸奔狀態(tài),因?yàn)閔ttp傳輸?shù)氖敲魑模芸赡茉趥鬏斶^(guò)程中被竊聽(tīng),偽裝或篡改。
那么,弄個(gè)https不就好了嗎?
https的確能夠極大增加網(wǎng)站的安全性,但是用https得先買(mǎi)證書(shū)(也有免費(fèi)的),對(duì)于個(gè)人站點(diǎn)或者不想弄證書(shū)的情況下,那最起碼也得對(duì)用戶密碼進(jìn)行一下加密吧。
流程圖
先看一下大體流程圖,首先,我們用工具生成公鑰和私鑰,將其放入server端,前端發(fā)起請(qǐng)求獲取公鑰,拿到公鑰后對(duì)密碼進(jìn)行加密,然后將加密后的密碼發(fā)送到server端,server端將用密鑰解密,最后再用sha1加密密碼,存入數(shù)據(jù)庫(kù)。

生成RSA公鑰和密鑰
既然選擇RSA加密,那么首先得有工具啊,常見(jiàn)的有openssl,但這里不介紹,感興趣的請(qǐng)自行查閱,對(duì)于node而言,我介紹一個(gè)不錯(cuò)的庫(kù)Node-RSA,我們將用它來(lái)生成RSA公鑰和密鑰。
RSA是一種非對(duì)稱(chēng)加密算法,即由一個(gè)密鑰和一個(gè)公鑰構(gòu)成的密鑰對(duì),通過(guò)密鑰加密,公鑰解密,或者通過(guò)公鑰加密,密鑰解密。其中,公鑰可以公開(kāi),密鑰必須保密。
用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)該隔一段時(shí)間換一次,比如每次服務(wù)器重啟時(shí)。
前端加密
核心代碼如下:
<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對(duì)密碼進(jìn)行加密
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對(duì)其進(jìn)行加密,詳細(xì)用法請(qǐng)參考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) {
// 不加會(huì)報(bào)錯(cuò)
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ù)庫(kù)中的密碼是: ', password)
// 存入數(shù)據(jù)庫(kù)中
// store to db...
res.end('reg ok')
break
}
})
app.listen(3000, '127.0.0.1')
這里,我是用node自帶模塊crpto進(jìn)行解密,當(dāng)然,你也可以用Node-RSA的方法進(jìn)行解密。
最后
我們?cè)賮?lái)看一看前端請(qǐng)求的密碼信息:

這樣一串字符,即便被他人獲取,如果沒(méi)有密鑰,在一定程度上,他是無(wú)法知道你的密碼的。
當(dāng)然,關(guān)于網(wǎng)絡(luò)安全是一個(gè)大話題,本篇只是對(duì)其中的一小部分進(jìn)行介紹,歡迎留言討論,希望對(duì)您有幫助。,也希望大家多多支持腳本之家。
相關(guān)文章
Electron如何通過(guò)ffi-napi調(diào)用dll導(dǎo)出接口
文章介紹了如何在Electron項(xiàng)目中使用ffi-napi模塊調(diào)用DLL文件,并詳細(xì)描述了環(huán)境搭建、安裝Electron和ffi-napi、配置Visual Studio和Python環(huán)境、解決常見(jiàn)問(wèn)題等步驟,感興趣的朋友跟隨小編一起看看吧2025-02-02
nodejs清空/刪除指定文件夾下面所有文件或文件夾的方法示例
這篇文章主要介紹了nodejs清空/刪除指定文件夾下面所有文件或文件夾的方法,通過(guò)兩個(gè)具體案例形式分析了node.js同步刪除文件/文件夾,以及異步刪除文件/文件夾的相關(guān)實(shí)現(xiàn)技巧,涉及遞歸遍歷與文件判斷、回調(diào)等相關(guān)操作,需要的朋友可以參考下2023-04-04
一文詳解npm如何更新項(xiàng)目最新依賴(lài)包
npm包的更新速度很快,為了將項(xiàng)目或者全局依賴(lài)更新到最新版本,下面這篇文章主要給大家介紹了關(guān)于npm如何更新項(xiàng)目最新依賴(lài)包的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
一文學(xué)會(huì)如何升級(jí)npm管理的各依賴(lài)版本
npm在前端開(kāi)發(fā)流程中提供了非常完善的自動(dòng)化工具鏈,已成為每個(gè)前端開(kāi)發(fā)者必備的工具,下面這篇文章主要給大家介紹了關(guān)于如何升級(jí)npm管理的各依賴(lài)版本,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09

