Phalcon で CSRF 対策を行う
内容
Phalcon では CSRF 対策としてワンタイムトークンを生成して用いる.
関連するメソッドは下記の通り.
Security#checkToken()
Security#getToken()
Security#getTokenKey()
Security#getSessionToken()
使用例
ビュー側では 下記のように生成する.
<input type="hidden" name="<?php echo $this->security->getTokenKey() ?>"
value="<?php echo $this->security->getToken() ?>"/>
volt の場合の例.
{{ hidden_field(security.getTokenKey(), "value": security.getToken()) }}
コントローラ内では以下のようにしてチェックする.
if ($this->security->checkToken()) {
// TODO: CSRF トークンチェックが成功した場合
}
フォーム内で生成して isValid()
したい場合は下記のようフォーム内で Indentical
バリデーションクラスを用いてチェックするようにする例.
public function initialize() {
// CSRF
$csrf = new Hidden('csrf');
$csrf->addValidator(new Identical(array(
'value' => $this->security->getSessionToken(),
'message' => 'CSRF validation failed'
)));
$this->add($csrf);
}
{{ form.render('csrf', ['value': security.getToken()]) }}
checkToken()
は第一引き数に名前を取るので csrf
という名前でフォームをレンダリングした場合は checkToken('csrf')
でもチェックできる.
使う場合の注意点
- ビューなどでトークンを埋め込む場合は
getToken()
を用いたほうがよい-
getSessionToken()
はgetToken()
を呼ばない限りはセットされないため
-
-
getToken()
は1ページ内で一回のみの呼び出しとしたほうがよい-
checkToken()
やgetSesssionToken()
で使われる値は最後にgetToken()
を呼んだ値となる - (追記) 最後に呼ばれた
getToken()
を使うため別タブで開いたりするとバリデーションエラーになる.認証必須なページならログインフォームで一回生成した後ずっとgetSessionToken()
を用いるような実装のほうが利便性は高そう.
-
-
indexAction()
の場合getToken()
を読んでいなくてもgetSessionToken()
の値が変更されているらしく,checkToken()
や Form クラスでの csrf トークンが正しくてもエラーになってしまう様子(詳細動作未確認).-
indexAction()
内では csrf トークンを確認するような処理を行わないほうがよさそう./
でなにかやりたい場合は Route クラスを用いて別アクションに変更するようにしたほうがよさそう 参考 .
-
ここらへんは フォーラム に書かれてる事が多いのでちょっと見てみると良いかもしれない.
付録
一度も getToken()
が呼ばれていないセッションで POST や GET された値が空の場合になぜか checkToken()
が true を返す.ただし通常利用では空で送信することはないので問題ないはず.
参考
ドキュメント
セキュリティ — Phalcon 1.3.1 documentation
http://docs.phalconphp.com/ja/latest/reference/security.html#csrf
サンプル
vokuro/app/forms/LoginForm.php at master · phalcon/vokuro
https://github.com/phalcon/vokuro/blob/master/app/forms/LoginForm.php
volt で書いた時の例
problems with csrf - Discussion - Phalcon Framework
http://forum.phalconphp.com/discussion/1658/problems-with-csrf
getToken()
を複数呼ぶことについて
CSRF tokens and many forms at one page - Discussion - Phalcon Framework
http://forum.phalconphp.com/discussion/345/csrf-tokens-and-many-forms-at-one-page
checkToken()
が true を返す例外について
checkToken() is not enough check value for CSRF Attack? - Discussion - Phalcon Framework
http://forum.phalconphp.com/discussion/2388/checktoken-is-not-enough-check-value-for-csrf-attack-
indexAction で getSessionToken()
がちゃんと動かない
PhalconPHP - How to get CSRF working on index page | Ole Aass