nodejs之cookie和session

因爲最近工做須要又將node撿了起來。翻了下以前的筆記,想着把幾篇比較詳細的整理下分享出來。第一篇就來講說常常會用到的cookie&session。node

由來

衆所周知http是一個無狀態的協議,服務端沒法跟蹤客戶端的狀態。那麼就會致使一個問題,如咱們以管理員身份登陸一個後臺管理系統,登陸成功後跳轉到管理頁面,那在咱們進行操做時,服務器怎麼知道咱們是否已經登陸過了呢?mysql

cookie

爲了解決上面的問題,cookie誕生了。redis

cookie是http協議中的一部分,瀏覽器向服務器發請求,成功後服務器向瀏覽器返回一個cookie,那麼之後瀏覽器向服務器發送的全部請求都會攜帶這個cookie。sql

首先安裝express框架,固然你也可使用koa。這裏演示代碼都是express。
在express中cookie不是自帶的,因此須要安裝對應的中間件進行操做,koa中的cookie就是框架自帶的就不須要另外安裝。數據庫

安裝cookie-parser中間件express

npm i cookie-parser -Dnpm

寫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的讀取和設置都很簡單,設置的時候有一些可選參數,安全

  • domain:存儲的域名,cookie是不跨域的,而且存儲在主域名中子域名是能夠訪問到的,可是若是存在子域名中那麼主域名是沒法訪問的。因此這裏通常是存在主域名,避免子域名訪問不到cookie。
  • path:存儲路徑,與domain相似,因此通常也是指定根路徑。
  • maxAge:有效期(毫秒)

運行下代碼,而後到瀏覽器中查看剛剛寫入的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');
})
  • httpOnly:設置cookie只能由服務器操做,前臺看不到
  • secure:只有在https的狀況下才能使用cookie
  • singed:設置cookie是否簽名

這裏我先現開啓簽名。而後運行代碼
在這裏插入圖片描述
能夠看到這回的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的存儲空間,因此咱們只簽名重要的信息。

session

cookie 雖然很方便,可是使用 cookie 有一個很大的弊端,就是存儲在瀏覽器,雖然說能夠對cookie進行簽名,可是也不能保證cookie的絕對安全,而且將重要的信息存在客戶端自己就是不安全的事情。同時cookie也受限於大小。爲了解決這些問題session也誕生了。

session 中的數據是保留在服務器端的。session不會單獨存儲,會有標識,這個標識叫作session_id 或者 token。而且session是強制加密的。

一樣咱們須要另外一箇中間件操做session,cookie-session
npm 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)

相關文章
相關標籤/搜索