Node.js: Cookie and Session
18 Aug 2015Cookie and Session。
Cookie 的特性
- Cookie 無法對使用者保密:使用者可以查看所有 Server 端傳送到 Client 端的 Cookie。
- 使用者可以刪除、停用 Cookie:使用者擁有對 Cookie 的控制權。
- 正規的 Cookie 可能會被竄改:當 Cookie 對特定伺服器發出請求,而伺服器信任這請求時,等於門戶洞開,歡迎被攻擊。例如:去執行被竄改後的 Cookie。因此,為了確保 Cookie 不被竄改,建議改用 Signed Cookie。
- Cookie 可用來進行攻擊:跨站指令攻擊(XSS)其中ㄧ項技術是使用 JavaScript 惡意修改 Cookie 的內容,因此不要信任由 Client 端回傳到 Server 端的 Cookie 內容。改善的方法是:
- 使用 Signed Cookie:因為 Server 端不接受竄改過的 Signed Cookie,且會重設回原本的值。
- 指定 Cookie 只能由伺服器修改。
- 使用者知道 Cookie 被濫用。
- 愛用 Session,而非 Cookie。Session 較 Cookie 簡單、不浪費使用者的儲存空間、安全。
補充說明
- XSS 攻擊:XSS 簡單說明和範例。如果擔心 Cookie 被 JavaScript 讀取和修改,則使用這段指令
setCookie("name","value",time()+86400,"/","domain",false,true)
。 其中最後一個參數是指定 HttpOnly,表示 Cookie 不能夠被 JavaScript 存取,目前主流瀏覽器皆有支援。 - What are “signed” cookies in connect/expressjs?:Signed Cookie 的簡單說明。
- xkcd Password Generator
外部認證
將 Cookie 保密是一個使得 Cookie 安全的必要方法,我們可以使用 xkcd Password Generator或憑證來保障其安全性。這裡選用憑證。建立一個 JavaScript 檔案 - credential.js
,將憑證存放在這支檔案裡面。記得,要加到.gitignore
,使其不受版本控管。
credential.js 部份。
module.exports = {
cookieSecret: 'your cookie secret goes here',
};
app.js 部份。
var credentials = require('./credential.js');
Express 裡的 Cookie
安裝 cookie-parser
npm install --save cookie-parser
載入模組 cookie-parser
在 app.js 中設定載入模組 cookie-parser
var cookieParser = require('cookie-parser');
app.use(cookieParser(credentials.cookieSecret));
使用 cookie-parser
設定 Cookie
假設在取得首頁時,設定兩組 Cookie:monster 和 signed_monster。
// get index page
router.get('/', function(req, res, next) {
// 取得各城市的氣象相關資訊
if (!res.locals.partials) {
res.locals.partials = {};
}
res.locals.partials.weather = getWeatherData();
// 取得首頁時,設定兩組Cookie:monster和signed_monster
res.cookie('monster', 'nom nom');
res.cookie('signed_monster', 'nom nom', { signed: true });
res.render('index', { title: 'Index' });
});
來看看結果。
讀取 Cookie
將剛剛設定的 Cookie 從 Server 端讀取。
var monsterCookie = req.cookies.monster;
var signedMonsterCookie = req.signedCookies.signed_monster;
刪除 Cookie
刪除 monster 這個 Cookie。
res.clearCookie('monster');
Cookie 的屬性
- domain:可將 Cookie 指定給特定的子網域。
- path:控制 Cookie 套用的路徑。
- maxAge:指定 Client 端的 Cookie 的保留時間,意即在多久後刪除,以毫秒為單位。若忽略則會在瀏覽器關閉後刪除。也可以用 expires 指定到期時間。
- secure:指定這個 Cookie 只會透過 HTTPS 來傳送。
- httpOnly:指定這個 Cookie 只能被 Server 端修改。
- signed:若設定為 true,則只能在
res.signedCookies
中使用,而不能在res.cookies
中使用。Server 端會拒絕被竄改的 Signed Cookie,且重設為原本的值。
Session
使用一個內含獨一無二識別碼的 Cookie,Server 端會用這個識別碼來取回適當的 Session 資訊。
安裝並設定 express-session
npm install --save express-session
在 app.js 中設定載入模組 express-session。
var credentials = require('./credential.js'),
session = require('express-session');
app.use(cookieParser(credentials.cookieSecret));
app.use(session());
使用 Session
req.session.userName = 'Pusheen';
var colorScheme = req.session.colorScheme || 'dark';
console.log(req.session.userName); // Pusheen
console.log(colorScheme); // Dark
delete req.session.userName; // remove session
console.log(req.session.userName); // undefined
補充說明
- Cookie Session:將所有資訊存在 Cookie 中,而只將非識別碼存在 Cookie 中,再由識別碼跟 Server 拿取資料。
使用 Session 來實作閃爍訊息
於是我們就可以利用 Session 來實作在Node.js:表單處理與檔案上傳(Form Handling and File Uploads)提到的,當使用者提交表單後,直接在頁面上顯示 Flash 訊息來提示使用者成功送出資料。
HTML 部份。
.{.{#if flash}.}.
<div>.{.{.{ flash.message }.}.}.</div>
.{.{/if}.}.
備註:由於部落格會把花括號吃掉,因此在左右加一個點,例如「.{.{ }.}.」。
app.js 部份。
提交表單後,設定 flash 訊息。如果存在 flash 訊息,則列印在畫面上,然後刪除。
app.post('/newsletter', function(req, res) {
var name = req.body.name || '',
email = req.body.email;
req.session.flash = {
type: 'success',
message: 'You have been signed up for the newsletter',
};
return res.redirect(303, '/thankyou');
});
index.js 部份。
取得 thankyou page 時列印 flash 訊息在畫面上。
// get thankyou page
router.get('/thankyou', function(req, res) {
res.locals.flash = req.session.flash;
res.render('thankyou', { title: 'thankyou' });
});
Demo。
這篇文章的原始位置在這裡-Node - Cookie and Session
由於部落格搬遷至此,因此在這裡放了一份,以便閱讀;部份文章片段也做了些許修改,以期提供更好的內容。