CodeIgniter3でajaxを行う際に403が返ってくる時の対処法2つ
CodeIgniter3でajaxを使っていると、適切なコードを書いているはずなのに403が返ってきた。
これを機に、CodeIgniterのajax周りについて調べたのでメモしておく。
開発環境
- CodeIgniter 3.1
- PHP 7.4.1
- Mac 10.14
CodeIgniterのajaxで403が返る原因
CodeIgniterでajaxを行う際に403が返る原因として、CodeIgniterのcsrf対策の設定が考えられる。(「クロスサイトリクエストフォージェリ - Wikipedia」)
CodeIgniterには、configs/config.php
内に以下のようなコードがある。
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_test_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;
$config['csrf_exclude_uris'] = array();
CodeIgniterのcsrg対策は、上記のコードの$config['csrf_protection'] = TRUE;
をTRUE
にすることで自動で行うようになっている。
あとは、Controller内で$this->load->helper('html')
としてhtmlヘルパーを呼び出し、viewで<?php echo form_open('post/create'); ?>
等とフォームを呼び出すことで、自動でcsrfトークンを追加してくれる。
しかし、問題は$config['csrf_regenerate'] = TRUE;
の部分。デフォルトではcsrfトークンは1回限りしか使えないようになっており、ajaxで何回も通信を送ることができないようになっている。
ajaxで403が返ってくる対策法2つ
以上のことを踏まえて、ajaxで403が返ってきた時の対処法は以下の2つが考えられる。
$config['csrf_regenerate']をFALSEにする
一番簡単な方法は、$config['csrf_regenerate'] = FALSE
のすることだ。これだけでcsrfトークンが毎回再発行されなくなり、ajaxで同じトークンを使い回せる。
セキュリティ的には少し甘くなるのが欠点だが、最も簡単な対策と言える。
ajaxのたびにトークンを再発行。
2つ目の方法は、ajaxでresponseを送るたびにトークンを再発行する方法。
CodeIgniterには$this->security->get_csrf_hash()
と言う再発行したcsrfトークンのハッシュ値を返すメソッドが用意されており、これを使えばうまく処理ができる。
参考:セキュリティクラス — CodeIgniter 3.2.0-dev ドキュメント
具体的には、Controller内では以下のように処理を書く。
<?php
$results = [
'content' => $content,
'csrf_token' => $this->security->get_csrf_hash(),
];
$this->output
->set_content_type('application/json')
->set_output(json_encode($results));
そしてajaxでresponseを受信した時に、formのcsrfトークンの値を変更すればOK.
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText);
let csrf_input = document.getElementsByName("csrf_test_name")[0];
content.innerHTML = response.content;
csrf_input.value = response.csrf_token;
}
}
}
もっと良い方法があるよ、という場合はコメントください。