前置き
はい、CodeIgniter2なんて化石です。
バージョンを3に上げれててばいいのも承知の上です。だがそれが簡単に出来ないから苦労してる事もあるわけです。
今回の困りごと
クッキーのセキュア属性をOnにした途端、元からフレームワークが提供しているcsrf対策が導入されている箇所が壮大なエラーを披露してくれた。
なんで〜の調査にちょっと時間がかかったので備忘録を残しつつ他の人にも役に立てばと思い、わかった事と最速の対策案をまとめました。
調査結果でわかった事
CodeIgniter2では、クッキーのセキュア属性がOnになっている場合は、HTTPS通信であるかどうかを判断して、HTTPSを確認できた時のみCSRFクッキー発行している。
ここまではお利口。
問題は「HTTPS通信であるか」にありました。
ロードバランサやWAFなどを使っている環境では、
$_SERVER['HTTPS']
だけでは判断が出来ないのに、フレームワークの処理ではこれしか見ていなかった事が今回起きてしまったエラーの原因でした。
最速にできる対策
問題を起きした処理は、CodeIgniter3でいい感じに修正されていたので、それを使って問題解消します。
なるべくコアのクラスではなく、拡張クラスで実施おススメします。
修正Before/Afterのコード
Before
if ($secure_cookie)
{
$req = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : FALSE;
if ( ! $req OR $req == 'off')
{
return FALSE;
}
}
そもそも、あんまり綺麗なコードではないですね。
After
CodeIgniter3の最新安定バージョンから、この処理を引っ越す。
いい感じの使い回しが効くコードで流石に綺麗にもなったなと、成長を少し眺めてしまいました。
/**
* Is HTTPS?
*
* Determines if the application is accessed via an encrypted
* (HTTPS) connection.
*
* @return bool
*/
public function is_https()
{
if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
{
return TRUE;
}
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https')
{
return TRUE;
}
elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
{
return TRUE;
}
return FALSE;
}
そして、既存の判定処理の代わりに動くものを以下の通りに修正。ついでに少しだけきれいに(リファクタリングが楽しくて我慢できない人)。
if ($secure_cookie && ! $this->is_https())
{
return FALSE;
}
ちょっとふりかえって
古いフレームワークを使うと色々困る事が多いからこそ、テストコードとかテストそもそもが重要だなと思う日でもあり、最新のコードがGitHubで公開されていて助かるな~と実感する日でもありました。
細かいところ(変数名をキャメルにとか~)も修正したかったけど、リファクタリングし過ぎは事故の元、なので今回は我慢しました。