Webアプリの脆弱性としてCSRF(クロスサイトリクエストフォージェリ)というよく知られた攻撃があります。詳細はここでは割愛しますので、IPAのページでご確認下さい。
Yesodは比較的堅牢で脆弱性を作り込みにくいフレームワークだと思いますが、CSRFについてもフレームワークレベルで対策が盛り込まれています。
formでの対策
YesodのHTMLテンプレートであるhamlet内でformを扱う場合、CSRF対策となるトークンをform内のhidden項目として持つ必要があります。
が、この項目はYesodが自動生成してくれるので、プログラマはMFormを返す関数の定義で、Htmlを引数に取るようにすればいいです。
createForm :: Html -> MForm Handler (FormResult Text, Widget)
なお・・・MFormを返す関数は型宣言が面倒だが、Foundation.hsにこれを簡単に書くためのtype宣言があります。
-- | A convenient synonym for creating forms.
type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget)
これを使うと次のように書けます。
createForm :: Form Text
Ajaxの場合
Ajaxの場合、トークンをリクエストにセットするのはプログラマの責任となります。
ただYesodは、scriptタグの中にCSRF対策のトークンを、トップレベルのスコープのvar変数として定義してくれています。
これをAjaxリクエストのヘッダにセットすれば、サーバ側でYesodがCSRFトークンをチェックしてくれます。
下記はSuperAgentを使ったAjax実行の例です。
request.get(url)
.set(csrfHeaderName, csrfToken) // Yesodが定義しているvar変数を使っている
.end(function(err, res) {
...
});
なおこれらのヘッダの設定を怠ると、YesodはCSRFチェックをNGとし、下記のようなHTMLを返してきます。
<p>A valid CSRF token wasn't present in HTTP headers or POST parameters. Check the Yesod.Core.Handler docs of the yesod-core package for details on CSRF protection.</p>
CSRF対策のトークン値を得る
あまり必要な局面が見当たらないですが、Haskellコードの中でCSRF対策のトークンの値を得ることができます。reqToken
関数を使います。
token <- getRequest >>= return . maybe "" id . reqToken