express v3.0.6
csrfミドルウェア
express アプリケーションでCSRFの脆弱性に対応するためには、 csrf ミドルウェアを導入します。(CSRF対策が必要な場面では、必ず通信をSSLやTLSで暗号化する必要がありますが、この記事ではそこには触れません。)
csrf ミドルウェアでは、以下の処理を行います。
- セッション開始時にトークンを生成し、セッション変数に保存する
- GET, HEAD, OPTIONS 以外のメソッドでHTTPリクエストを受け取ったときに、リクエストbodyで渡されたトークンの値と,セッションに保存した値を照合する
ミドルウェアの設定
csrfミドルウェアはセッションにトークンを保存するので、必ずsession ミドルウェアの後に呼び出します。(14行目)
また以下の例では、ビューからセッションの_csrfの値にアクセスできるように、res.locals._csrf に値をコピーしています。(16行目)
app.js
//~
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(express.csrf());
app.use(function(req, res, next){
res.locals._csrf = req.session._csrf;
next();
})
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
//~
ビューの設定
HTMLフォームに、セッションの _csrf の値を保存するhiddenフィールドを追加します。(2行目)
form.jade
form(method="POST", action="/") input(type="hidden", name="_csrf", value= _csrf) br input(type="submit")
Errorのハンドリング
フォームで送信した_csrf の値とセッションに保存しているトークンの値が一致しないと、Errorオブジェクトが生成されるので、Errorをハンドルする処理を追加します。
以下の例では、レスポンスステータスに403をセットし、403エラー用のエラーページを表示させています。(20行目)
app.js
//~
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(express.csrf());
app.use(function(req, res, next){
res.locals._csrf = req.session._csrf;
next();
})
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(err, req, res, next){
if(err.name === "Forbidden"){
res.status(403).render('403')
} else {
next(err)
}
})
});
//~