CakePHPでAjaxを利用する際には、csrfトークンについての知識が必要になります。
今回の記事では、具体的な使い方について紹介します。
CakePHPでのAjaxの使い方
Templates/samples/demo.php
(テンプレートのどこかに下記のコードを挿入)
<input type="hidden" name="_csrfToken" autocomplete="off" value="<?= $this->request->getAttribute('csrfToken') ?>">
sample.js
const submitData = {};
submitData.hoge = 1;
submitData.piyo = 2;
$.ajax({
type: 'post',
url: '/samples/demo',
headers: { 'X-XSRF-TOKEN': $('input[name="_csrfToken"]').val() },
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('input[name="_csrfToken"]').val());
},
data: {
"_csrfToken": $('input[name="_csrfToken"]').val(),
"data": submitData
},
processData: false,
contentType: false,
}).then(function (data) {
console.log(data);
});
このようにしないと、ajaxで送信した際に以下のようなエラーが出ます。
Missing CSRF token body
CakePHPではデフォルトでCSRFによるサイト攻撃に対する対策がなされており、普通にAjaxを組み込むだけではうまく動きません。
CSRFとは何か?については下記外部サイト様をご参照ください。
CSRF(クロスサイトリクエストフォージェリ)とは?被害と対策も
CSRFとはクロスサイトリクエストフォージェリの略であり、Webアプリケーションの脆弱性を利用したサイバー攻撃の一種です...
外部サイトからAjaxでアクセスしたい場合
CakePHPで作ったウェブサービスに、外部サイトからAjaxでアクセスしたい場合があります。
このような場合には、当然CSRFトークンが仕込まれていないので、普通にAjaxでアクセスするとエラーが発生してしまいます。
外部サイトからのAjaxアクセスを受け入れたいページだけ、CSRF対策を停止する必要があります。
コードの編集箇所と解説
src/Application.phpの関数middleware()を編集します。
●コード全体
//src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
//追記する箇所①
$csrf = new CsrfProtectionMiddleware(['httponly'=>true]);
$csrf->skipCheckCallback(function ($request) {
$controller = $request->getParam('controller');
$action = $request->getParam('action');
//https://ドメイン/hoge/piyoで表示するページはcsrf対策を無効にする
if ($controller=="Hoge" && $action == "piyo") {
return true;
}
return false;
});
$middlewareQueue
// Catch any exceptions in the lower layers,
// and make an error page/response
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime'),
]))
// Add routing middleware.
// If you have a large number of routes connected, turning on routes
// caching in production could improve performance. For that when
// creating the middleware instance specify the cache config name by
// using it's second constructor argument:
// `new RoutingMiddleware($this, '_cake_routes_')`
->add(new RoutingMiddleware($this))
// Parse various types of encoded request bodies so that they are
// available as array through $request->getData()
// https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware
->add(new BodyParserMiddleware())
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/security/csrf.html#cross-site-request-forgery-csrf-middleware
//ここをコメントアウトする
//->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
//]));
//追記する箇所②
->add($csrf);
return $middlewareQueue;
}
●追記する箇所①:特定のコントローラ、アクションのみcsrfチェックをスキップする
$csrf = new CsrfProtectionMiddleware(['httponly'=>true]);
$csrf->skipCheckCallback(function ($request) {
$controller = $request->getParam('controller');
$action = $request->getParam('action');
//https://ドメイン/hoge/piyoで表示するページはcsrf対策を無効にする
if ($controller=="Hoge" && $action == "piyo") {
return true;
}
return false;
});
●追記する箇所②:①で追記した設定を反映する
//コメントアウトする
//->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
//]));
//追記する箇所②
->add($csrf);
これで特定のページのみCSRF対策を無効にできます。
サイト全体でCSRFチェックを外す方法もありますが、セキュリティー的に危険なので、部分的に外すようにしましょう。
コメント