
WEBアプリケーションのセキュリティの一つとしてCSRF対策(CSRFの詳細についはIPAを参照)が挙げられます。CakephpではCSRFコンポーネントを利用するのが通常でしょう。
そこで必要になるのが CSRFトークン。単にajaxを利用しようとすると、「CSRF token mismatch」エラーが発生します。そして、バージョンによる差異はあるかもですが、SecurityComponetエラーも発生。([Cake\Controller\Exception\AuthSecurityException] '_Token' was not found in request data.)エラー内容: リクエストデータにトークンがありまへんで
Cakephp は Formヘルパーを利用し、$this->Form->create() すれば、自動でCSRFトークンを生成してくれます。よって、通常のフォーム作成ではFormヘルパーさえ活用していれば、CSRF対策を特に気にしてなくもOK。(※CSRFコンポーネントは有効であること)
以下、AJAXの場合のCSRFトークンの利用法です。
step
1FormヘルパーでCSRFトークンを自動生成して利用
<?php // CSRFトークン発行(AJAXで利用) ?> <?= $this->Form->create(null) ?> <?= $this->Form->end() ?>
これでChromeなどで右クリック「検証」でコードを確認すると、「_csrfToken」という形でCSRFトークンが自動生成されているのを確認できます。
step
2AJAXのbeforeSendでトークンセット
<script>
$(function(){
$('要素名指定').on('click', function() {
// Formヘルパーで生成したCSRFトークンの値を取得
var csrf = $('input[name=_csrfToken]').val();
$.ajax({
type: 'POST',
url: '<?= $this->Url->build(['controller' => 'コントローラ名', 'action' => 'アクション名']) ?>',
data: 送信したいjsonデータとか,
// ここが本丸。CSRFトークンをセット
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', csrf);
},
}).done(function(data) {
// 成功時処理
}).fail(function() {
// 失敗時処理
});
});
});
</script>
AJAXで送信する時、beforeSendでリクエストヘッダーに「X-CSRF-Token」としてトークンをセットしておきます。
step
3AJAXのurl先コントローラーでセキュリティアクションのajax許可
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Security->setConfig('unlockedActions', ['許可したいアクション名']);
}
※Securityコンポーネントは親コントローラーAppControllerでロードしておくこと(initialize()内、$this->loadComponent('Security');)
これで通過できるようになります。
AJAX通信確認方法:
ChromeのF12キーでDevelopmentToolsを起動し、「Network」タブの「Fetch/XHR」が選択されている状態で画面をリロードし、AJAXアクションが発生する箇所をクリックするなどすれば200(成功)レスポンスが確認できるはず。
・Securityコンポーネント(CSRF)
https://book.cakephp.org/3/ja/controllers/components/security.html#csrf
・非推奨だけどCSRF無効
https://book.cakephp.org/3/ja/controllers/components/csrf.html
・CSRF対策(クロスサイトリクエストフォージェリ)について
https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_6.html