IT技(ji)術互(hu)動(dong)交流(liu)平台

彩神注册官网

作者︰佚名  發布日(ri)期︰2020-02-20 06:16:26

 撰寫于 2020年02月20日(ri) 修改于 2020年02月20日(ri) 分類編程(cheng)雜記(ji) 標簽AngularJS /Express /Node.js /Waterline /安全

很多(duo)的網絡(luo)應用都有基于用戶名密碼的登陸功能(neng),而絕大多(duo)數的登陸都毫無安全性可(ke)言(yan),不夸張的說,大多(duo)數的程(cheng)序員根本(ben)不知道怎樣去保(bao)證用戶名和密碼的安全。

彩神注册官网

要(yao)想一(yi)個登陸系統安全,至少要(yao)保(bao)證以(yi)下(xia)幾個方面。

彩神注册官网

很多(duo)人對于用戶的原始密碼安全,還停(ting)留(liu)在(zai)不被非法第(di)三方獲取的層面上xi)  shi)際上xi)  濟藶氳淖畬笸wei)脅,往往來自于系統的開發人員和服務器的管(guan)理人員。這些人可(ke)能(neng)是有意(yi)收集,也可(ke)能(neng)是無意(yi)泄露,往往是用戶原始密碼的泄露的罪魁禍首。在(zai)構建登陸系統的時(shi)候(hou),應該從根本(ben)上避免,做到只(zhi)有用戶自己和鍵盤記(ji)錄器才知道原始密碼。

那如何做到這一(yi)點呢?首先一(yi)點就是一(yi)定要(yao)在(zai)客戶端進(jin)行密碼加密,這可(ke)以(yi)使得後端拿到的密碼已經是加過(guo)密的,一(yi)來服務器接觸不到原始密碼,二來就算通(tong)信被監听,第(di)三方就算拿到了可(ke)以(yi)用來登陸的客戶端加密密文,也無法獲知用戶的原始密碼。

彩神注册官网

密碼加密不同于普通(tong)的加密,一(yi)是內容重要(yao),二是密碼的驗(yan)證根本(ben)不需要(yao)原文,要(yao)檢查一(yi)個密碼是否正確,只(zhi)需要(yao)看它(ta)加密的結果與正確的密碼加密的結果是否一(yi)致即可(ke)。確定了這兩點,對于加密的方法,就只(zhi)要(yao)求同一(yi)個字符(fu)串加密後會得到同樣的密文。哈(ha)希(xi)完全滿足(zu)了這一(yi)要(yao)求。

在(zai)哈(ha)希(xi)算法中,首選是 SHA2 系列,雖然安全由于 SHA1 的原因(yin)而被質疑,但至少目前還沒有證明(ming)有什(shi)麼紕漏。MD5 由于用得太多(duo),而且彩虹表(biao)實(shi)在(zai)過(guo)于泛濫,並不推薦(jian)使用。

另(ling)外一(yi)個問題,哈(ha)希(xi)一(yi)遍是不是就夠了呢?當然不,不僅要(yao)多(duo)次哈(ha)希(xi),而且yi)掛yao)與用戶名一(yi)類的數據混加,比如,可(ke)以(yi)使用下(xia)面的方式來在(zai)客戶端加密原始密碼︰

sha256( sha265(sha265(password)) + sha265(username))

這樣,不僅可(ke)以(yi)增加密文反(fan)推原文的難度(du),還加入(ru)用戶名,使得就算密碼相同,不同用戶的密文也完全不一(yi)樣。

在(zai)客戶端的加密,基本(ben)上也就只(zhi)能(neng)到這一(yi)步了,因(yin)為一(yi)個最主要(yao)的問題是,客戶端的加密算法是公開的。

彩神注册官网

雖然在(zai)客戶端對密碼進(jin)行了加密,但無論是算法,還是混入(ru)的用戶名,都是公開了的。剩(sheng)下(xia)的加密,就tuo)枰yao)留(liu)給後端了。

由于對同一(yi)字符(fu)串進(jin)行哈(ha)希(xi)的結果是恆(heng)定的,所以(yi)知道了算法和密文,理論上是可(ke)以(yi)反(fan)推出密碼的,反(fan)推的難度(du)取決(jue)于用戶原始密碼的復雜度(du)。那如何才能(neng)夠讓反(fan)推的難度(du)指數級增大呢?答案是在(zai)原始密碼密文的基礎(chu)之(zhi)上xi) 偌尤ru)一(yi)個隨(sui)機字符(fu)串,從而達(da)到讓用戶的密碼更(geng)復雜的效果。這個隨(sui)機字符(fu)串,便是鹽。

後端獲取到客戶端傳來的密碼之(zhi)後,再通(tong)過(guo)加you)喂ha)希(xi)進(jin)行再加密。比如像下(xia)面這樣︰

sha256( sha256(username + sha256(password + salt)) + salt + sha256(username + salt))

注(zhu)意(yi),鹽的保(bao)存非常關鍵,務必將它(ta)與用戶信息分開存放。

彩神注册官网

現在(zai)密碼已經分別在(zai)客戶端和後端多(duo)次哈(ha)希(xi),還加了鹽,好像已經很安全了。但其實(shi),我們(men)還可(ke)以(yi)更(geng)安全。那就是經常變更(geng)鹽,讓用戶信息表(biao)中的密文字段(duan)值也經常變化。這樣,除非同時(shi)拿到用戶信息和鹽,否則(ze)依然無效。

那什(shi)麼時(shi)候(hou)變更(geng)鹽和密文呢?由于後端是不存儲(chu)客戶端si)ha)希(xi)的密文的,所以(yi)只(zhi)有在(zai)登陸的時(shi)候(hou),才能(neng)夠進(jin)行鹽和密文的修改。

彩神注册官网

這個想法好像有點不靠譜(pu),但實(shi)際上xi) 沒 綣zhi)是作為單(dan)純的登陸憑證,其實(shi)是可(ke)以(yi)像密碼一(yi)樣加密的。因(yin)為無論是注(zhu)冊、登陸還是找yi)孛藶耄 疾恍枰yao)用戶名的原文。但注(zhu)意(yi),用戶名只(zhi)能(neng)哈(ha)希(xi),不能(neng)加you)危 裨ze)就沒什(shi)麼依據去找鹽了。

用戶名的哈(ha)希(xi)可(ke)以(yi)分兩jiang)糠鄭 yi)是客戶端si)ha)希(xi),到了服務器端,可(ke)以(yi)進(jin)行再次哈(ha)希(xi)。

在(zai)本(ben)文的 Demo 中,將不對用戶名哈(ha)希(xi)。

彩神注册官网

在(zai)應用層面基本(ben)上已經很安全了。接下(xia)來就是客戶端和通(tong)信的安全。客戶端的環境基本(ben)不可(ke)控,所以(yi)只(zhi)能(neng)在(zai)通(tong)信的安全上想辦法了。不過(guo)其實(shi)也不用想什(shi)麼多(duo)的辦法,直接使用 HTTPS 就tuo)辛恕/p>

彩神注册官网

上面總結了怎樣保(bao)證一(yi)個用戶名密碼登陸系統的安全,這里(li)再來看看一(yi)個滿足(zu)上述要(yao)求的登陸系統的登陸流(liu)程(cheng)。注(zhu)冊流(liu)程(cheng)相對來講(jiang)簡單(dan)一(yi)些,所以(yi)就不再詳細(xi)介(jie)紹。

Demo 是一(yi)個簡單(dan)的 Web 用戶名密碼登陸系統,代碼示例(li)也取自于它(ta)。

瀏覽器登陸

瀏覽器主要(yao)完成以(yi)下(xia)工(gong)作︰

獲取用戶輸入(ru)的用戶名及密碼 通(tong)過(guo)輸入(ru)的用戶名和密碼,進(jin)行哈(ha)希(xi),得到瀏覽器端密文 將用戶名和密文提交給後端

主要(yao)代碼如下(xia),取自 client/app.js ︰

// 密碼與用戶名的哈(ha)希(xi)function encryptPwd(username, password) { username = username.toLowerCase(); return sha256( username + sha256 ( sha256(sha256(sha256(password))) + sha256(username) ) );}$scope.login = function(){ // 檢查用戶名和密碼的合xi)ㄐ裕 熱縭欠袷淙ru),長(chang)度(du)是否足(zu)夠等(deng) if($scope.check()) { return; } $scope.successMessage = ''; $scope.errorMessage = ''; $scope.status = 'loading'; // 向後端提交登陸請求 $resource('/user/login') .save({ username: $scope.username, password: encryptPwd($scope.username, $scope.password) }, function(res){ $scope.status = 'done'; $scope.successMessage = 'login successful!'; }, function(reason){ $scope.status = 'done'; $scope.errorMessage = reason.data 'failed'; });};

彩神注册官网

後端的驗(yan)證流(liu)程(cheng)如下(xia)︰

獲取前端提交的用戶名及瀏覽器端密文 根據用戶名,在(zai)數據庫中查詢(xun)出對應的鹽 id 通(tong)過(guo)鹽 id 取出對應的鹽,再通(tong)過(guo)用戶名、瀏覽器端密文和鹽算出後端密文 根據用戶名和後端密文到用戶表(biao)查詢(xun),如果有結果,則(ze)表(biao)明(ming)登陸信息正確,返回給瀏覽器登陸成功的響應 生成新的鹽,算出新的後端密文,並將兩者更(geng)新到數據庫中

 

實(shi)現的代碼如下(xia),取自 app/controllers/user.server.controller.js ︰

function encryptPwd(usr, pwd, salt){ usr = usr.toLowerCase(); return sha256( sha256(usr + sha256(pwd + salt)) + salt + sha256(usr + salt) )}function login(req, res, next){ // 用戶名密碼獲取和檢查已省略 // 根據用戶名,獲取鹽 id req.models.user .findOne({select:['username', 'saltId'], where: {username: username}}) .exec(function(err, userDoc){ if(err) return next(err); if(!userDoc) return next(new Error('username not exists')); // 取鹽 req.models.salt .findOne({id: userDoc.saltId}) .exec(function(err, saltDoc){ if(err) return next(err); if(!saltDoc) return next(new Error('can NOT find salt')); // 根據用戶名、密碼和鹽推算出密文 var pwdHash = encryptPwd(username, password, saltDoc.salt); // 在(zai)數據庫中核對用戶名和密文 req.models.user .findOne({select: ['id'], where: {username: username, password: pwdHash }}) .exec(function(err, doc){ if(err) return next(err); if(!doc) return next(new Error('password error')); res.json({  username: username }); return updateSalt(saltDoc, userDoc, password, next); }); }); });}

彩神注册官网

前面返回給用戶成功登陸的響應之(zhi)後,調用了更(geng)新鹽和密文的方法,該方法具(ju)體流(liu)程(cheng)如下(xia)︰

生成並存儲(chu)新鹽 根據新鹽、用戶名和瀏覽器端密文,生成新的後端密文 存儲(chu)後端密文到用戶信息表(biao)

實(shi)現如下(xia),取自 app/controllers/user.server.controller.js ︰

function updateSalt(saltDoc, userDoc, passwordInputed, next){ saltDoc.salt = Math.random().toString(15).substr(3, 27); saltDoc.save(function(err){ if(err) return next(err); userDoc.password = encryptPwd(userDoc.username, passwordInputed, saltDoc.salt); userDoc.save(function(err){ if(err) return next(err); return next(); }); });}

彩神注册官网

Demo 托(tuo)管(guan)在(zai) Github 上。前端采用 AngularJS + Bootstrap ,後端使用 Node.js + Express + MongoDB ,是一(yi)個典(dian)型(xing)的 MEAN 應用 。

數據存儲(chu)這塊,使用了 Waterline 這個 ORM 中間件(以(yi)前也曾經寫過(guo)兩篇介(jie)紹文章,可(ke)供(gong)參考︰ Node.js ORM 數據操作中間件 Waterline 、 在(zai) Express 項目中使用 Waterline )。使用它(ta)的目的主要(yao)是為了將用戶信息和鹽存儲(chu)到jiang)煌 牡胤健1ben)例(li)中將鹽用 sails-disk 存儲(chu)到了文件中,用戶信息用 sails-mongo 存儲(chu)到了 MongoDB 中。

git clone https://github.com/stiekel/safe-username-password-login.gitcd safe-username-password-loginnpm inpm i -g gulpgulp

再在(zai)瀏覽器中打(da)開 http://localhost:7102/ 即可(ke)。

 

Tag標簽︰用戶名  密碼  系統  
  • 彩神注册官网

彩福彩票官网About IT165 - 廣告服務 - 隱(yin)私聲明(ming) - 版權(quan)申明(ming) - 免責條款(kuan) - 網站地圖 - 網友(you)投(tou)稿 - 聯(lian)系方式
本(ben)站內容來自于互(hu)聯(lian)網,僅供(gong)用于網絡(luo)技(ji)術學習,學習中請遵循相關法律法規
彩神注册官网 | 下一页