本文首發(fā)于:我的個人博客 墨客
本文源碼地址: https://github.com/edwardwang0302/encrypt_demo
如需轉(zhuǎn)載請注明出處
這篇文章會講什么?
寫這篇文章的目的主要是想講講常見的密文存儲方式,從明文存儲晌梨,到Md5加密玄柏,再到“加鹽”(salting)和多次md5加密玩讳,涉及到的只是加密方面非常小的一部分。
涉及到的環(huán)境和工具
如果你是把本文當(dāng)做一個擴(kuò)展來看,完全沒有必要安裝和配置以下的環(huán)境倘屹,安裝這些只是為了方便演示
- Node.js環(huán)境 Npm包管理 Express框架 Nodemon來熱加載 body-parser插件解析post請求的body
- MongoDB數(shù)據(jù)庫 mongoose操作數(shù)據(jù)庫
- PostMan工具
正式開始
在開始之前我們假設(shè)你的電腦已經(jīng)安裝了Node.js環(huán)境茬末,Npm包管理以及MongoDB
初始化工程
mkdir encrypt
cd encrypt
npm init
接下來一路回車厂榛,就是提示一些npm工程初始化的信息,如下圖
安裝Express,Nodemon噪沙,Mongoose
npm i -g nodemon
npm i -S express mongoose body-parser
稍微等待之后炼彪,我們目錄下面多了node_modules目錄,里面是一些依賴
開始寫后臺代碼
mkdir server //存放server代碼目錄
cd server
touch server.js //server代碼
touch model.js //存放數(shù)據(jù)庫相關(guān)
touch user.js //存放和user相關(guān)的后臺代碼
打開model.js文件正歼,復(fù)制下面代碼:
const mongoose = require('mongoose')
// 連接mongo 并使用encrypt這個集合
const DB_URL = 'mongodb://localhost:27017/encrypt'
mongoose.connect(DB_URL)
// 定義存儲用戶數(shù)據(jù)的模型
const models = {
user:{
'user':{type:String, require:true},
'pwd':{type:String, require:true},
},
chat:{
}
}
// 根據(jù)模型創(chuàng)建集合
for(let m in models) {
mongoose.model(m, new mongoose.Schema(models[m]))
}
module.exports = {
getModel:function(name) {
return mongoose.model(name)
}
}
打開user.js文件辐马,復(fù)制下面代碼
const express = require('express')
const Router = express.Router()
const models = require('./model')
const User = models.getModel('user')
Router.get('/all', function(req, res) {
// 查找所有的用戶信息
User.find({}, function(err, doc) {
return res.json(doc)
})
})
Router.post('/regist', function(req, res) {
const { user, pwd } = req.body
User.findOne({user}, function(err, doc) {
if(doc) {
return res.json({code:1, msg: '用戶名存在'})
}
User.create({user, pwd}, function(e, d) {
if(e) {
return res.json({code:1, msg: '注冊失敗'})
}
return res.json({code:1, msg: '注冊成功'})
})
})
})
module.exports = Router
打開server.js文件,復(fù)制下面代碼:
const express = require('express')
const bodyParser = require('body-parser')
const userRouter = require('./user')
const app = express()
// 用于解析post請求的body
app.use(bodyParser.json())
// 把所有user操作都路由到/user這個url下面
app.use('/user', userRouter)
app.listen(9000, function() {
console.log('Hi, guys! I am listening prot 9000')
})
前后端聯(lián)調(diào)
這里其實(shí)不是真正意義上的前后端聯(lián)調(diào)局义,這為了簡單使用PostMan工具發(fā)送一個請求喜爷,大家可以隨意用自己喜歡的工具
- 啟動MongoDB
如果你已經(jīng)安裝好了MongoDB,直接使用mongod命令就可以啟動
mongod
- 啟動后臺服務(wù)器
nodemon server/server.js
看到下圖說明啟動成功
-
使用PostMan發(fā)送注冊請求
-
查看已注冊的用戶
可以看到這里我們的用戶信息已經(jīng)保存了萄唇,不過是明文保存的檩帐,這點(diǎn)當(dāng)然不能接受,下面我們將怎么變?yōu)槊芪?/p>
從明文到md5加密
加密中最簡單的方式是使用md5這種單向的不可逆的方式另萤,我們這里借助utility這個工具來加密
- 停掉剛剛的服務(wù)湃密,安裝utility
npm i -S utility
- 修改user.js
...省略一些內(nèi)容
// 引用utility
const utils = require('utility')
...省略一些內(nèi)容
Router.post('/regist', function(req, res) {
const { user, pwd } = req.body
User.findOne({user}, function(err, doc) {
if(doc) {
return res.json({code:1, msg: '用戶名存在'})
}
// 這里使用md5加密
User.create({user, pwd: utils.md5(pwd)}, function(e, d) {
if(e) {
return res.json({code:1, msg: '注冊失敗'})
}
return res.json({code:0, msg: '注冊成功'})
})
})
})
module.exports = Router
- 啟動服務(wù),重新注冊一個用戶u2 密碼123
再次查看請求 http://localhost:9000/user/all
可以看到這已經(jīng)使用md5加密過了四敞,這種方式依然存在著一些問題泛源,我們下面展開討論
從md5加密到“加鹽”
到目前為止我們已經(jīng)使用了最簡單的加密方式md5,可是有些網(wǎng)站使用“彩虹表”的方式可以逆向這種加密,舉個例子:
打開 http://www.cmd5.com 直接輸入我們的密文: 202cb962ac59075b964b07152d234b70 點(diǎn)擊查詢
天哪理論上不可逆的md5居然被破譯了忿危,怎么降低這種概率呢(注意這里說的是降低)达箍,那么就要使用我們之前提到的“加鹽”(salting)的方式。加鹽其實(shí)就是我們自己加密的過程中加入一串復(fù)雜的字符串铺厨。
我們修改user.js文件缎玫,在module.exports前面加入下面函數(shù)定義
// 加密加鹽
function salting(pwd) {
const salt = 'i_wanna_be_bestx8yza6!@#IUHJH~~'
return utils.md5(pwd+salt)
}
修改加密部分
User.create({user, pwd: utils.md5(pwd)}, function(e, d)
// 將上面的這句換成
User.create({user, pwd: salting(pwd)}, function(e, d)
重啟服務(wù),再次注冊一個u3 密碼為123解滓,注冊成功后我們可以看到密碼赃磨,再去剛剛的網(wǎng)站發(fā)現(xiàn)已經(jīng)不能解析了
多次md5增加復(fù)雜度
修改上面提到的salting函數(shù),多加一次md5加密
function salting(pwd) {
const salt = 'i_wanna_be_bestx8yza6!@#IUHJH~~'
return utils.md5(utils.md5(pwd+salt))
}
總結(jié)
至此洼裤,我們大致完成了一般簡單的系統(tǒng)加密過程的演進(jìn)煞躬,對于一些有更高要求的加密系統(tǒng)來說,上述的方式依然是不安全的逸邦,只是簡單的增加了破譯的時間成本和空間成本恩沛;加密方式目前有很多,當(dāng)然也已經(jīng)不屬于我們“管中窺豹”的簡單定義了缕减,大家有興趣可以再去深入研究雷客,就先寫到這里吧。