axiosからPOSTするとCSRFチェックで引っかかる(異なるセッションとして認識される)

下記のようなアプリケーションを考えます。

概要

  • 入力フォームのあるWebアプリ
    • バックエンドはPHP
    • フロントエンドはVue.js
    • 通信はAjax(フォームを描画するためのいくつかのパラメータのGETも、フォームに入力した内容のPOSTも)

流れ

  1. フロントのURLへアクセスし、バックエンドからいくつかのパラメータを取得(この際、CSRF対策用のトークンも発行)、フォームをVue.jsで描画 (※a)
  2. フォームで入力
  3. フォームの入力内容をaxiosでAjax送信
  4. バックエンドのPHPはAjax通信で送信されたパラメータをチェック (※b) し、実際の処理を行う
上記の内容のうち、 (※a)(※b) の部分(実際にサーバにアクセスする部分)でトークンを発行したりチェックしたりしています。 CSRF対策の処理についてはとっても簡単なCSRF対策 – Qiitaを参考にさせて頂いています。

現象

上記の (※a)(※b) でセッションをスタートさせているのですが、このセッションIDが異なる。 セッションIDが異なれば、とっても簡単なCSRF対策 – Qiitaの判定は不一致になるのでコケます。 この原因は何だろうか、とずっと悩んでおりました。

原因

原因としては、やはりというかクロスオリジンでした。Vue.jsの開発環境ですとポート番号8080でアプリケーションが開かれますが、PHPは普通に80で待ち受けていました。 ポートが異なれば異なるオリジンと判定されるため、セッションの引継ぎが行われず、結果として不一致が起きていたということのようです。 そのため対策としてはCORSの設定をしてあげれば良いということになります。

対策

axiosでGETやPOSTする前にヘッダ情報を付与することでクリアできました(PHP側は予めヘッダを許可していたため)。

GET時

const axiosPost = axios.create({
    xsrfHeaderName: 'X-CSRF-Token',
    withCredentials: true
})
Promise.all([
    axiosApi.get(this.api.hoge)
]).then(([result]) => {
    //処理
})
//以下略

POST時

const axiosPost = axios.create({
    xsrfHeaderName: 'X-CSRF-Token',
    withCredentials: true
})
axiosPost.post(URI + 'api/hoge', this.senddata)
    .then(response => {
        console.log(response)
    })
    .catch(error => {
        console.log(error)
    })
こんな感じです。 ……気付けば「ああそうか」ということではあるのですが、なかなか気付かず嵌まっておりました……。

参考

CSRF対策

axios

CORS

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。