1.為什么說要利用簽名防止cookie被惡意篡改
我們在瀏覽器輸入用戶名和密碼發送post請求到后端服務器,后端服務器驗證合法,返回響應,並Set-Cookie
為sessionid=***;username=water
,然后瀏覽器接受到響應發Set-Cookie
,於是將其存入內存或硬盤中;瀏覽器端再次發起請求,帶上Cookie信息sessionid=***;username=water
,請求修改自己的頭像信息,服務器根據sessionid
驗證當前用戶已登錄,根據username
,查找數據庫中的對應數據,修改頭像信息,這是一個正常的cookie設置與利用cookie的過程。但是我們為什么說要防止Cookie被篡改呢?這是因為cookie是存儲在客戶端的,這時用戶可以任意修改cookie值,比如如果當前用戶知道username
的作用,修改username=fire
,根據username
,查找數據庫中的對應數據,並修改了頭像信息,這樣就暴露出數據被惡意篡改的風險。其實就是服務端無法保證張三請求修改數據時到底是不是張三自己要求修改,也可能是李四是在惡意篡改張三的數據。這時我們就要給cookie增加簽名,比如服務器接收到請求中的Cookie項username=fire||34sdklkas
,然后使用簽名生成算法secret(fire)=666
,得到的簽名666
和請求中數據的簽名不一致,則證明數據被篡改,不予通過,所以cookie中不應該存儲敏感數據,應該根據SessionID將敏感數據存儲在后端,取數據時根據SessionID去后端服務器獲取,對於一些重要的Cookie項,應該生成對應的簽名來反之被惡意篡改。
- 簽名就能夠確保安全嗎 我們只通過用戶名這個cookie來判斷登錄的是哪一個用戶,雖然增加了簽名,而且秘鑰我們也不知道,看起來很難偽造簽名cookie,但是只要原始值相同的情況下,簽名也是相同的,這匯總情況下就很容易偽造了,而且我們要確保秘鑰的生成算法不被泄露。
- Express中cookie-parser中間件的使用
cookie-parser中間件用來對cookie進行解析,主要包括普通cookie的解析和簽名cookie的解析。
-
簡單用法
最簡單的使用就是cookie的設置與解析,cookie的設置使用res.cookie方法,cookie的解析使用cookie-parser中間件
cookie-parser中間件 需要導入,不能直接使用
1 // 導入express 2 const express=require('express') 3 // 導入cookie中間件 4 const cookieParser = require('cookie-parser'); 5 6 const app = express(); 7 // 使用cookie-parser解析客戶端傳入的cookie 加密解密 8 app.use(cookieParser()); 9 // 向客戶端發送cookie 10 app.get('/send',(req,res)=>{ 11 res.cookie('name','nihao',{maxAge:60*1000}) 12 res.send('向客戶端發送cookie') 13 }) 14 // 接收服務器端傳入的cookie 15 app.get('/receive',(req,res)=>{ 16 // cookies 是保存前面所有的cookie 17 // res.send('接收到的cookie-->'+req.cookies.name) 18 19 }) 20 21 22 app.listen( 3000,()=>{ 23 console.log(`serve running at http://localhost:3000`) 24 })
-
cookie簽名、解析
出於安全的考慮,我們通常需要對cookie進行簽名
主要要注意一下幾點:
-
cookieParser
初始化時,傳入secret(參數)
作為簽名的秘鑰。- 設置cookie時,將
signed
設置為true
,表示對cookie進行簽名。 - 獲取cookie時,可以同時通過
req.cookies
,也可以通過req.signedCookies
獲取。
1 // 導入express 2 const express=require('express') 3 // 導入cookie中間件 4 const cookieParser = require('cookie-parser'); 5 6 const app = express(); 7 // 使用cookie-parser解析客戶端傳入的cookie 加密解密 8 app.use(cookieParser('aaa')); //secret 9 // 向客戶端發送cookie 10 app.get('/send',(req,res)=>{ 11 res.cookie('name','nihao',{maxAge:60*1000,signed:true}) 12 res.send('向客戶端發送cookie') 13 }) 14 // 接收服務器端傳入的cookie 15 app.get('/receive',(req,res)=>{ 16 // cookies 是保存前面所有的cookie 17 res.send('接收到的cookie-->'+req.signedCookies.name) 18 19 }) 20 21 22 app.listen( 3000,()=>{ 23 console.log(`serve running at http://localhost:3000`) 24 })