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