Express教程05:Cookie

閱讀更多系列文章請訪問我的GitHub博客,示例代碼請訪問這裏

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

其意義如下:

  1. s表示該Cookie爲簽名Cookie
  2. test123表示該Cookie設置的值
  3. 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,所以簽名不可濫用,只用來保護重要的數據即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章