#共有SSLでお手軽セキュア→失敗
とっても便利なSecurityComponent。以下のように記述すると、HTTP接続時、自動的にHTTPSへリダイレクトしてくれます。
public function beforeFilter() {
$this->Security->blackHoleCallback = 'forceSSL';
$this->Security->requireSecure();
}
public function forceSSL() {
$this->redirect('https://'.env('SERVER_NAME').$this->here);
}
しかしさくらインターネットのレンタルサーバー環境では、SSLの判定に失敗します。
https付きでアクセスしても、SSLではないと判定されてリダイレクトループに。なんでや。
#悪いのはどいつだ
SecurityComponent.phpを読んでみると、下記のようにsslの判定を行っていました。
if (!$this->request->is('ssl')) {
if (!$this->blackHole($controller, 'secure')) {
return null;
}
}
試しにコメントアウトするとブラックホールに吸われなくなったので、このロジックを修正すれば良さそうです。
CakeRequestを読むと、$_detectorsに$_SERVER変数からの抽出条件が記載されています。
protected $_detectors = array(
...
'ssl' => array('env' => 'HTTPS', 'value' => 1),
...
);
さくらの共有SSLでは、「HTTPS」の代わりに「HTTP_X_SAKURA_FORWARDED_FOR」としてIPアドレスを出力してくれます。
なのでこうしました。
protected $_detectors = array(
...
// 'ssl' => array('env' => 'HTTPS', 'value' => 1),
'ssl' => array('env' => 'HTTP_X_SAKURA_FORWARDED_FOR', 'pattern' => '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/'),
...
);
正規表現でIPアドレス(v4)のパターンを記述しています。
ただ、接続環境によってはIPv6で返ってきたりするかもしれないので、ちょっと不安ですね。
#コンポーネントを使わない方法
コントローラ中でSecurityコンポーネントを使用しないなら、手っ取り早くenv('PARAM')で判断するのが簡単です。
public function beforeFilter() {
if(is_null(env('HTTP_X_SAKURA_FORWARDED_FOR'))) {
$this->redirect('https://'.env('SERVER_NAME').$this->here);
}
}