CakePHP2.x フォームのPOSTでCSRF判定されハマったときに確認すること
はじめに
普通のフォームの場合は殆どおこらないが、選択肢によりフォームの表示切り替えをしたり、AjaxでPOSTさせたりした場合に、POSTしたのに、リダイレクトされてしまい、うまく動かない!なんでだ!とハマってしまったときに確認する事項を紹介します。
ハマる原因はなにか?
SecurityComponent と CSRF
POSTしたのにリダイレクトされるのは、SecurityComponent
の仕業です。なぜそうなるかというと、SecurityComponentが「このPOSTリクエストはCSRFなので、不正だ!」と判定しているのです。
CSRFについては、詳しい人がいると思うのでその人に任せますが、簡単に言うと、HTMLやリクエストの改ざんにより、サイト運営者が意図しないデータをPOSTすることで、意図しないデータの保存や不具合を発生させる攻撃です。
一見やなSecurityComponentですが、実はとてもいいやつなのです。誤解しないでください。
SecurityComponentはどういうチェックをしているか?
POSTされた データの中に、_Token
という配列データが含まれるのはご存知でしょうか?
これが重要なのですが、SecurityComponentはこの _Token
内の fields
と key
をチェックしています。
POSTされたデータのフィールドと値を元に、ハッシュ値などを生成し、POSTされたfields
値とkey
値の値が一致しているかチェックしています。
該当箇所は以下
// lib/Cake/Controller/Component/SecurityComponent.php
protected function _validatePost(Controller $controller) {
$token = $this->_validToken($controller);
$hashParts = $this->_hashParts($controller);
$check = Security::hash(implode('', $hashParts), 'sha1');
if ($token === $check) {
return true;
}
$msg = self::DEFAULT_EXCEPTION_MESSAGE;
if (Configure::read('debug')) {
$msg = $this->_debugPostTokenNotMatching($controller, $hashParts);
}
throw new AuthSecurityException($msg);
}
で、POSTされたデータに_Token
を入れてるのは、 FormHelper がやっております。
という前提の元、ハマっている場合、以下を確認すると解決できる(はずです)。
チェックリスト
POSTのフィールドと初回表示のフォームのフィールドが同じか?
選択肢により、フォームが変わったりすることがある場合は CSRF 判定されてしまうので、入るかわからないフィールドはコントローラの beforeFilter()
などで、SecurityComponent
の disabledFields
プロパティに設定する必要があります。
function beforeFilter()
{
parent::beforeFilter();
$this->Security->disabledFields = array('ModelName.fieldName1', 'ModelName.fieldName2');
}
disabledFields
プロパティに設定すれば、SecurityComponentのチェックの際に該当フィールドを無視してチェックしてくれるので、CSRF判定されません。
※ 注意 ※
ただし、該当フィールドは悪意の第三者に任意の値をPOSTされるリスクを許容するという設定になるので、POSTの値を信じず、必ずバリデーション等値のチェックを行ってください。
_Token をPOST値に含めてるか?
AjaxなどでPOSTする値を明示的に指定し直している場合、_Token
の値を指定し忘れると CSRF 判定されてしまうので、明示的に指定してください。
$.ajax({
type: 'post',
url: 'URL',
dataType: 'json',
data: {
ModelName: {
fieldName1: $('#ModelNameFieldName1').val(),
fieldName2: $('#ModelNameFieldName2').val(),
},
// ※ これを指定する必要ありますよ
_Token: {
// もっと素敵なやり方ある気がするので詳しい方教えてください。
fields: $('input[name="data[_Token][fields]"]').val(),
key: $('input[name="data[_Token][key]"]').val(),
unlocked: $('input[name="data[_Token][unlocked]"]').val(),
}
},
// 以下省略
Formヘルパーを使ってるか?
HTMLで直接記載している場合、Formヘルパーが fields
値とkey
値を作る場合に計算されないので、SecurityComponentがチェックするのと差異が出るためCSRF判定されてしまうので、必ずFormヘルパーを利用して下さい。
最後に
僕自身このケースでハマること合計数十時間。コアライブラリのコードを読んでスッキリ理解してハマることがなくなりました。参考になれば嬉しいです。
Author And Source
この問題について(CakePHP2.x フォームのPOSTでCSRF判定されハマったときに確認すること), 我々は、より多くの情報をここで見つけました https://qiita.com/autumnlike/items/541a06ab1caea7525e27著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .