Express教程05:Cookie
Cookie儲存在瀏覽器,在瀏覽器請求伺服器時,其中的資料都會被髮送到服務端,常用來做使用者資訊校驗等。
但由於Cookie儲存在瀏覽器,容易受到篡改,安全性較差。
使用cookie-parser處理Cookie
處理Cookie,可以使用中介軟體cookie-parser
讀取Cookie
示例程式碼:/lesson05/server.js
使用cookie-parser中介軟體時,需要先通過server.use(cookieParser())
解析cookie,之後就可以在req.cookies
屬性中讀取到cookie的值。
在瀏覽器開啟http://localhost:8080/cookie
,在控制檯寫入cookie{"userName":"lee"}
。
// 使用cookie-parser中介軟體,解析Cookie server.use(cookieParser()) server.get('/cookie', (req, res, next) => { // 讀取cookieParser解析的Cookie console.log(req.cookies) res.send(`cookies: ${JSON.stringify(req.cookies)}`) }) 複製程式碼
在瀏覽器開啟http://localhost:8080/cookie
,服務端列印結果為:{"userName":"lee"}
。
設定Cookie
示例程式碼:/lesson05/server.js
設定Cookie可以用Express自帶的方法res.cookie。
方法的第一個引數為設定的屬性名,第二個引數為屬性值,第三個引數為配置項,例如:
server.get('/cookie', (req, res, next) => { // express自帶的設定Cookie方法 res.cookie('userName', 'lee', { // 設定該Cookie只可以由服務端訪問,即前端JavaScript無法訪問document.cookie獲取該值,但控制檯還是可以檢視和修改 httpOnly: true, // 只有通過HTTPS請求的Cookie才被使用,否則都認為是錯誤的Cookie // secure: true, // 設定儲存Cookie的域名,瀏覽器查詢Cookie時,子域名(如translate.google.com)可以訪問主域名(google.com)下的Cookie,而主域名(google.com)不可以訪問子域名(如translate.google.com)下的Cookie // 本地測試可直接設定為localhost domain: 'localhost', // 設定儲存Cookie的路徑,瀏覽器查詢Cookie時,子路徑(如/map)可以訪問根路徑('/')下設定的Cookie,而根路徑('/')無法訪問子路徑(如/map)下設定的Cookie path: '/', // 通過expires設定Cookie過期時間為14天后 // expires: new Date(new Date().getTime() + 14 * 86400000), // 通過maxAge設定Cookie過期時間為14天后 maxAge: 14 * 86400000, }) // 讀取cookieParser解析的Cookie console.log(req.cookies) res.send(`cookies: ${JSON.stringify(req.cookies)}`) }) 複製程式碼
在瀏覽器的控制檯中,可以看到設定的Cookie為{"userName":"lee"}
,有效期是14天。
Cookie的簽名
示例程式碼:/lesson05/server.js
Cookie的簽名即是使用一個儲存在服務端的金鑰對Cookie進行加密,Cookie中儲存的資料是經過金鑰加密的,因此客戶端如果對Cookie進行修改,服務端校驗就無法通過。
設定金鑰
若需要給Cookie進行簽名,首先需要給cookieParser的第一個引數傳入一個字串金鑰:
// 解析Cookie server.use(cookieParser( // 簽名用金鑰,需要保密,僅儲存在服務端 'NpLRTpy1vbBzEw2JcAxpf970kOk2RViDn5wKwrMv' )) 複製程式碼
簽名Cookie
這樣就可以開始設定簽名Cookie了,只需要在res.cookie
方法的配置引數中設定signed: true
屬性:
res.cookie('password', 'test123', { httpOnly: true, domain: 'localhost', path: '/', maxAge: 14 * 86400000, // 開啟該Cookie的簽名模式 signed: true }) 複製程式碼
在瀏覽器開啟http://localhost:8080/cookie
,可以看到Cookie中被設定了password
屬性,其值為s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
。
如果用decodeURIComponent方法進行解碼,結果為s:test123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
。
其意義如下:
-
s
表示該Cookie為簽名Cookie -
test123
表示該Cookie設定的值 -
HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
表示對該值的簽名,也就是說當服務端接收到該Cookie時,會使用服務端的金鑰對test123
進行簽名,再與HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
進行對比,如果正確才可以使用。
此時可以看到服務端列印結果為signedCookies: {"password":"test123"}
。
在客戶端修改簽名的Cookie
如果使用者在客戶端對簽名的Cookie進行了修改,例如在瀏覽器控制檯,將password改為s%3Atest456.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
。
此時在服務端列印的結果為signedCookies: {"password":false}
,表示校驗失敗。
同時瀏覽器中的Cookie值被重新修改為了s%3Atest123.HrZ44MCUeLXj0uZAzTpCXWduflOsmfBs5XsuK4eTMvg
。
除非使用者在修改簽名的Cookie的值時,將該值的簽名一起修改,否則校驗是無法通過的。
但由於簽名是由服務端的金鑰計算而成,因此這個值通常是安全的。
不過,因為對Cookie進行簽名,會佔用更多的Cookie儲存空間,而Cookie在瀏覽器中最多隻能儲存4K,所以簽名不可濫用,只用來保護重要的資料即可。