FuelPHPでCSRFが動かない件

FuelPHPの入力フォームでFuelが提供している機能を使ってCSRF対策を入れました。

やり方は、下記のサイトを参考にしました。
FuelPHP1.7、CSRF対策としてセキュリティトークンを使う

CSRF対策の導入

具体的な方法は下記の通り。

1./fuel/app/config/config.phpの「token_salt」にトークンを設定。

'token_salt'            => 'xxxxxxxxxxxxxxx', // 任意のトークン

2.View側のフォーム内で下記を埋め込む。

<?= Form::csrf() ?>

3.受け側のControllerでチェック

if ( ! Security::check_token())
{
	// たとえばエラーページに飛ばす。
	throw new HttpNotFoundException;
}

これで準備OK!
設定も簡単であとは画面を動かして確認するだけ。

期待通りに動かない

、、、がしかし、

if ( ! Security::check_token())

が常にfalseになる!!

とりあえずGoogle先生に聞いてみると下記のサイトがヒット
なぜうちのFuelPHPは、Security::check_token()が常にfalseだったのか。

なるほど~と思ったが、うちとは環境が違うので今回は解決策にはならず…
ほかにもいろいろ調べながら別プロジェクトの該当部分を見ながら差分を確認しつつ設定を合わせながら動かしたが一向に改善されず。

解決した!?

アレコレ調べるうちに、Fuelのフォーラムで気になる記載を見つけました。
How to Fight CSRF?

英語なので内容の理解はアレですが、
さっと読んだ感じだと、/fuel/app/config/config.phpの「csrf_expiration」に秒数を指定すれば動きましたみたいに書いてある(と理解した)。

確かに秒数を指定すれば期待通りの動作になったので、
これで解決かなと思ったが、別のプロジェクトではこれを指定しなくても動いてる点が引っかかる。。。

原因特定

一緒に原因を調査していたメンバーから、なぜかpost後の処理が2回走っているとの報告が。
そしてその原因がおそらくfaviconの設定が悪いとのこと。

そういえばとふと思い出したのが下記のリンク。
FuelPHPでsubmitの二度押し防止方法(chrome)

原因を調べる過程で下記のリンクを見ていたのですが当時はスルーしていましたが、
文中のここ重要でした。

Security ClassのCSRF対策がうまく動かず、faviconを置いたら解決したという妙な事があったので

確かに、開発時点ではfaviconがなかったので

<link rel="icon" href="">

の形でTODO記載していたがそれがいけなかった。。。

該当部分を削除したら正常に動くことを確認。めでたしめでたし。

結論

  • CSRFが動かなかったらfaviconの設定が正しいかどうかを疑う
  • faviconは最終的には事態を書き換えれば済む話なので、最初からしっかりした記述にしとく

後日段

「どうやってfaviconが原因って特定したんですか?」

「view側の記述を上から一行一行消して試してみました。」

「!?」

私の場合は、こういったフレームワークで提供されている機能については、
原因を特定するために設定周りから始まりCoreのソースの解析などからアプローチします。
(view側をとりまく環境はあまり重視していない)

それでも原因がわからない時には、泥臭いけど時view側をシンプルにして動くか確認することが重要であるという教訓になりました。

  • このエントリーをはてなブックマークに追加
  • Pocket
  • LINEで送る