■なぜだかCSRF対策が暴発してブラックホールに頻繁に吸い込まれる
こちらのCopyContentDetectorで、頻繁にブラックホールに吸い込まれる現象が発生していました。フォームを表示して、普通にボタンを押すだけでCSRFで例外発生していました。これがまた、再現性が低く、起こるときは頻繁に起こる状態でよくわからない挙動をしていました。
CakePHPのバージョンは2系です。
■考えられる要因
faviconのパスが通っていないとだめ、などいろいろ情報はありましたがリンク切れも無く、なんで発生しているのかよくわからない状態でした。ソースコードを追ったり、ログをたくさん仕込んでみると以下のことがわかりました。
・CSRFトークンを保持できる数はデフォルトで100個まで。超えると古い順から削除される
CSRFトークンを保持する数が決まっています。デフォルトで100個までとなっています。上限まで記録されると、古い順から削除をされいきます。
・AJAXや通常のページにアクセスしてもSecurityComponentが読み込まれていると、CSRFトークンが生成される
アクセスするだけでSecurityコンポーネント読んでるコントローラにアクセスすると、CSRFトークンが生成されます。
・csrfUseOnceをFalseに指定していた
再利用ができるように、csrfUseOnceをFalseに設定していた。その結果、利用してもトークンが削除されることはありません。
上記の事から、アクセスされまくる→一定期間が経過するとCSRFトークンが消える時がある→CSRF対策で死亡。の可能性が高いです。
■今回した対応
今回した対応は以下のとおりです。
・csrfUseOnceはfalseのまま運用。
・上限値を多くしました。65536個まで利用できるようにしました。コントローラで以下のように書くと変わります。だいたい、上限値に行く前にタイムアウトなどで消えていくので、上限まで行くことはないでしょう。
$this->Security->csrfLimit = 65536;
・無駄なページでトークンを生成しないようにしました。フォームが存在しないページで、SecurityComponentを中身を読むと以下を設定すると大丈夫みたいですね。このパラメータなんだ?
$this->request->params['requested'] = 1;
今日一日見ていましたが、大体大丈夫みたいですね。セッション周りは、ユーザのブラウザや環境にも強く依存するので、とてもとても面倒くさいですね。つらかった。。