摘要:基于以上原因,很多管理都是基于實現的。在經過中間件的時候就會自動完成的有效性驗證延期重新頒發以及對中數據的獲取了。上述代碼只是對于請求的靜態處理,整個用戶管理的另一個方面則是狀態的切換用戶的登陸登出以及用戶數據的獲取。
基礎概念
Session管理是Web Application的基礎也是一個老生常談的話題。為了方便后文的展開,更重要的是確認自己清晰的理解了整個Session管理的概念,我在此還是決定贅述的整個流程。如果你已經對于Session概念非常清晰的話,可以跳過本節不影響對于后文的理解。
HTTP協議在設計的時候是無狀態的。這是一個很關鍵的概念,意味著服務器在處理請求的時候,并不關注這個請求是誰發來的。這對于以提供內容為核心的Web1.0,例如門戶網站,非常適合。然而對于以應用服務為核心的Web 2.0而言,服務器端必須有能力從請求中提取出請求者的身份信息,以在請求者不用反復輸入身份的情況下,提供連續的服務。
實現請求身份驗證的方式很多,其中一種廣泛接受的方式是使用服務器端產生的Session ID結合瀏覽器的Cookie實現對Session的管理,一般來說包括以下4個步驟:
服務器端的產生Session ID
服務器端和客戶端存儲Session ID
從HTTP Header中提取Session ID
根據Session ID從服務器端的Hash中獲取請求者身份信息
上圖是一個使用Redis Cluster來實現對Session管理的流程,但本質上除了redisMatrix.get和redisMatrix.set以外,和一般的Session管理流程是一致的。
簡單來說,一個請求到達的時候,服務器會先判斷是否帶有Session信息。如果有,則根據Session ID去數據庫中查找是否具有對應的用戶身份信息。此處可能會出現Session失效、非法的Session信息等可能性,那么服務器視同無Ssession信息的情況,重新的產生一個隨機的字符串,并且在Http返回頭中寫入新的Session ID信息。另一者,如果服務器成功獲取了用戶的身份信息則以該身份為請求者提供服務。
使用Express和Redis對Session管理的實現Redis是一個非常適合用于Session管理的數據庫。第一,它的結構簡單,key-value的形式非常符合SessionID-UserID的存儲;第二,讀寫速度非常快;第三,自身支持數據自動過期和清除;第四,語法、部署非常簡單。基于以上原因,很多Session管理都是基于Redis實現的。
Express已經將Session管理的整個實現過程簡化到僅僅幾行代碼的配置的地步了,你完全不用理解整個session產生、存儲、返回、過期、再頒發的結構,使用Express和Redis實現Session管理,只要兩個中間件就足夠了:
express-session
connect-redis
廢話不多說還是上代碼:
var express = require("express"); var session = require("express-session"); var RedisStore = require("connect-redis")(session); var app = express(); var options = { "host": "127.0.0.1", "port": "6379", "ttl": 60 * 60 * 24 * 30, //Session的有效期為30天 }; // 此時req對象還沒有session這個屬性 app.use(session({ store: new RedisStore(options), secret: "express is powerful" })); // 經過中間件處理后,可以通過req.session訪問session object。比如如果你在session中保存了session.userId就可以根據userId查找用戶的信息了。
req在經過session中間件的時候就會自動完成session的有效性驗證、延期/重新頒發、以及對session中數據的獲取了。
上述代碼只是對于請求的Session靜態處理,整個用戶管理的另一個方面則是狀態的切換(用戶的登陸、登出)以及用戶數據的獲取。
exports.signin = function(params, req, res){ var username = params.username; var password = params.password; //查找用戶信息,看是否滿足登陸條件 var user = findUser(username, password); if(user){ //成功獲取用戶對象 req.session.regenerate(function(){ req.user = user; req.session.userId = user.id; req.session.save(); //保存一下修改后的Session res.redirect("/account"); }); } else{ //用戶信息不符合,登陸失敗 } } exports.signout = function(req, res){ req.clearCookie("connect.sid"); req.user = null; req.session.regenerate(function(){ //重新生成session之后后續的處理 res.redirect("/signin"); }) } exports.persist = function(req, res, next){ var userId = req.session.userId; //通過user id去數據庫里面查找User對象 var user = findUserById(userId); if(user){ req.user = user; next(); } else{ //該用戶不存在 } }Session的安全問題
SessionId就如同請求者的身份證,一旦被攻擊者惡意獲得,攻擊者便可以偽裝成請求者對服務器發起請求,也就是我們經常聽到的會話劫持(Session/Cookie Hijack)
關于會話劫持的原理推薦大家去看這篇文章
基于上述實現方法的Session管理,我認為基本上可以排除
暴力破解SessionId
惡意植入固定SessionId
兩種可能,因為uid的庫基本上可以保證SessionId的隨機性;而傳遞SessionId則依賴HTTP請求頭中的Cookie信息而非URL,同時在用戶登錄立刻更換SessionId。
唯一的可能性來源于Session的監聽,而對于這種攻擊有效的兩種防止辦法是:
Https
很多網站僅僅在Login的階段使用Https防止用戶的用戶名、密碼信息被監聽者獲取,但是隨后的SessionId同樣有可能被監聽者獲取而偽造登錄者的身份信息。因此更加推薦的方式是所有的信息傳遞全部使用Https實現,這樣即使監聽著截獲了信息也無法破解其中的內容。關于如何使用NodeJS建立一個HTTPS的server可以參考《HTTPS的原理和NodeJS的實現》 這篇文章
httpOnly
Express在options中提供了httpOnly的屬性,此屬性默認值為true,這個屬性保證了Cookie的信息不能夠通過JavaScript腳本獲取。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85588.html
世界上任何一個擁有用戶數據的 web 應用都必須處理 sessions。作為一名開發者,我們必須要知道它們是什么以及如何處理它們。在這篇文章中,我想要分享的是: session 是什么? session 如何存儲數據? 你如何決定存放 session 數據的位置? 在 sessions 工作時,你必須意識到的安全性上的影響有哪些?在一些示例代碼中,我將會運用?session npm modul...
摘要:當會話過期或被放棄后,服務器將終止該會話。原來中間件生成的是一個對象,里面包含了信息。這個有一個過期時間,比如,上面代碼中設置的是小時。也就是說,小時后,這個在瀏覽器中會自動消失。 前言 在上一篇中node中的cookie,對cookie進行了相關介紹,本篇將繼續前行,對session進行說明。 session是什么 session不就是會話嘛,那什么是會話呢?會話是一個比連接粒度更大...
摘要:當會話過期或被放棄后,服務器將終止該會話。原來中間件生成的是一個對象,里面包含了信息。這個有一個過期時間,比如,上面代碼中設置的是小時。也就是說,小時后,這個在瀏覽器中會自動消失。 前言 在上一篇中node中的cookie,對cookie進行了相關介紹,本篇將繼續前行,對session進行說明。 session是什么 session不就是會話嘛,那什么是會話呢?會話是一個比連接粒度更大...
閱讀 3773·2021-11-11 11:02
閱讀 3504·2021-10-11 10:57
閱讀 3612·2021-09-22 16:00
閱讀 1851·2021-09-02 15:15
閱讀 1336·2019-08-30 15:56
閱讀 1015·2019-08-30 15:54
閱讀 2737·2019-08-30 12:43
閱讀 3545·2019-08-29 16:06