symfony1.2のCSRF対策について
こんにちは、小川です。
symfony1.2ではsfFormクラスを用いてフォームのレンダリングや入力項目のバリデーションを行います。このsfFormクラスにはCSRF対策も実装されているのはご存じでしょうか。
今回はこのCSRF対策が具体的にどのように行われているかをお話ししたいと思います。
先にどのような手法で対策を行うかですが、フォームごとに異なるトークンをHTML上に埋め込み、その値をバリデーション時にチェックするという方法で対策を行っています。
具体的にどのようにトークンが生成され、どのようにチェックを行っているかは後ほど詳しく説明します。
CSRF対策を有効にするためにはどうすれば良いでしょうか。Jobeetなどでsymfony1.2について学んだ方はご存じかと思います。
CSRF対策は各アプリケーションごとに設定可能で、アプリケーション作成時に以下のようにすることで有効になります。
$ symfony generate:app --escaping-strategy=on --csrf-secret=myUniqueSecret frontend
通常symfonyコマンドのgenerate:appタスクを用いてアプリケーションのスケルトンを生成しますが、タスク実行時にcsrf-secretというオプションを指定します。最初の説明でトークンを埋め込むと説明しましたが、このトークンを生成するときのソルト値として使用する値を指定します。上記の例ではmyUniqueSecretがソルト値になります。
実際にcsrf-secretというオプションを指定してアプリケーションを生成した場合、アプリケーションのconfigディレクトリ内にあるsettings.ymlという設定ファイルの内容が変化します。
all:
.settings:
csrf_secret: myUniqueSecret
allのcsrf_secret という項目に、先ほどのcsrf-secretオプションの値が入っていると思います。もしgenerate:appタスク実行時にcsrf-secretを指定しなかった場合はfalseとなり、CSRF対策が有効になりません。もし有効に設定しなかった場合はsettings.ymlを直接変更してキャッシュをクリアすれば有効になります。
有効にするだけであればとてもシンプルですが、フォームクラスを利用するときにはどのような注意が必要なのでしょうか。通常フォームクラスには「ウィジェット」と「バリデータ」を指定することでフォーム要素の作成とバリデーションを行っていきます。CSRF対策のトークンはどのようにして扱えば良いのでしょうか。実際にコードを書いて説明していきます。
// lib/form/doctrine/UserForm.class.php
<?php
class UserForm extends BaseUserForm
{
public function configure()
{
$this->setWidgets(array(
'email' => new sfWidgetFormInput(),
));
$this->setValudators(array(
'email' => new sfValidatorEmail(array(), array(
'required' => 'メールアドレスを入力してください',
'invalid' => 'メールアドレスを正しく入力してください',
)),
));
}
}
// apps/frontend/modules/user/actions/actions.class.php
<?php
class userActions extends sfActions
{
public function executeNew(sfWebRequest $request)
{