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) } }) }); //~