因爲最近工做須要又將node撿了起來。翻了下以前的筆記,想着把幾篇比較詳細的整理下分享出來。第一篇就來講說常常會用到的cookie&session。node
衆所周知http是一個無狀態的協議,服務端沒法跟蹤客戶端的狀態。那麼就會致使一個問題,如咱們以管理員身份登陸一個後臺管理系統,登陸成功後跳轉到管理頁面,那在咱們進行操做時,服務器怎麼知道咱們是否已經登陸過了呢?mysql
爲了解決上面的問題,cookie誕生了。redis
cookie是http協議中的一部分,瀏覽器向服務器發請求,成功後服務器向瀏覽器返回一個cookie,那麼之後瀏覽器向服務器發送的全部請求都會攜帶這個cookie。sql
首先安裝express框架,固然你也可使用koa。這裏演示代碼都是express。
在express中cookie不是自帶的,因此須要安裝對應的中間件進行操做,koa中的cookie就是框架自帶的就不須要另外安裝。數據庫
安裝cookie-parser中間件express
npm i cookie-parser -D
npm
寫cookie跨域
安裝成功後,先引入cookie-parser。而後在任意路由中去嘗試寫一個cookie瀏覽器
const express = require('express'); const cookieParser = require('cookie-parser'); let server = express(); server.listen(8080); // 使用中間件 server.use(cookieParser()); server.get('/index',(req, res) => { // 使用了中間件後就能夠訪問req和res上的cookies對象 console.log(req.cookies); // 寫cookie res.cookie('num', 10, { // domain: 'xxx.com', // path: '/', maxAge: 24 * 3600 * 1000 }) res.send('ok'); })
cookie的讀取和設置都很簡單,設置的時候有一些可選參數,安全
運行下代碼,而後到瀏覽器中查看剛剛寫入的cookie
打開瀏覽器F12,到Application中找到Cookies,就能夠看到剛剛寫入的cookie,名字和值以及有效期都是咱們設置的。再次刷新後咱們也能夠在命令行中看到服務器打印的cookie。
簡單的cookie讀寫就完成了。
安全隱患
這裏咱們能夠知道cookie是存在瀏覽器中的,而且請求服務器的時候會一併帶過去。這樣就必定會有安全隱患,咱們先把服務器寫cookie的邏輯註釋掉,從新運行服務器,而後嘗試在瀏覽器中手動修改cookie。
這裏咱們將值修改成10000。刷新頁面後在命令行中能夠看到服務器獲取的值就是10000。
cookie就這樣很容易的在瀏覽器中被咱們修改了。若是cookie存了一些比較重要的數據,後果會很是嚴重。
cookie簽名
怎麼樣才能作到讓服務器驗證cookie準確性,讓服務器發現cookie是否被人爲修改。
就要用到cookie簽名。修改下服務器代碼。
// 密鑰 server.use(cookieParser( 'dasdasdasdasfewg315nkl23k1ml41m24kl1nm5kol312n5kl32n5oj3n4oi1jm4o1k2m4' ));
在使用cookieParser中間件的時候加入一個簽名密鑰,通常是隨機生成的一個字符串
而後在設置cookie的時候加入幾個參數。
server.get('/index',(req, res) => { // 簽名後的cookie須要經過signedCookies訪問 console.log(req.signedCookies); res.cookie('num', 10, { // httpOnly: true, // secure: true, signed: ture maxAge: 24 * 3600 * 1000 }) res.send('ok'); })
這裏我先現開啓簽名。而後運行代碼
能夠看到這回的cookie是一串亂碼。將亂碼複製出來是這樣的。s%3A10.y4%2BaUbiQxjUS%2FvaGtU%2BaZnAZ9WxVHXy3O0zr%2BgoCdGk
%3A表明":",轉換下獲得以下:s:10.y4%2BaUbiQxjUS%2FvaGtU%2BaZnAZ9WxVHXy3O0zr%2BgoCdGk
經過以上得出簽名後的cookie格式爲:s:值.簽名
這樣若是咱們嘗試修改其中的值,還會不會生效了呢?
將服務器設置cookie的代碼註釋掉,只打印cookie,而後在瀏覽器中修改cookie。
修改後的cookie由於沒法經過服務器的簽名驗證,因此是沒法獲取的。這樣就確保了cookie的安全性,雖然簽名能夠增長cookie的安全性,可是增大致積,因爲cookie只有4k的存儲空間,因此咱們只簽名重要的信息。
cookie 雖然很方便,可是使用 cookie 有一個很大的弊端,就是存儲在瀏覽器,雖然說能夠對cookie進行簽名,可是也不能保證cookie的絕對安全,而且將重要的信息存在客戶端自己就是不安全的事情。同時cookie也受限於大小。爲了解決這些問題session也誕生了。
session 中的數據是保留在服務器端的。session不會單獨存儲,會有標識,這個標識叫作session_id 或者 token。而且session是強制加密的。
一樣咱們須要另外一箇中間件操做session,cookie-sessionnpm i cookie-session -D
使用方式與cookie-parser相似,先引入cookie-session
const cookieSession = require('cookie-session');
而後進行循環密鑰簽名,密鑰通常是經過程序生成的,可能幾千幾萬條,這裏方便演示,只寫幾條。
server.use(cookieSession({ keys: ['dasdas21fsdffedsfds4das21321', 'safdas454325235325trgtrthdfthd', '21ed2rf3245r23r2354r235235'], maxAge: 20 * 60 * 1000 // 有效期20分鐘 }));
而後在接口中設置和獲取session
server.get('index', (req, res) => { console.log(req.session); res.session['num'] = 10; res.send('ok'); });
運行代碼,打開瀏覽器調試工具找到cookies,
cookie中有兩個值,一個是session,一個是session.sig
將服務器中設置session的代碼註釋掉,再刷新頁面,能夠看到命令行中就打印了咱們設置的session值。
就算其餘用戶經過session劫持拿到了咱們的session值,可是每一個用戶的session.sig簽名是經過循環密鑰生成的,數量龐大的循環密鑰相同的概率很小。而且在瀏覽器手動修改session後,服務器也會感知到這個session和session.sig不是對應的。確保數據的安全性。同時也能夠經過更換循環密鑰和減小session有效期來提高安全性。
須要注意的是session是存在服務器的文件中。讀寫比較消耗性能。咱們能夠將其保存在redis、內存、數據庫中以優化性能。(如使用mysql-session)