ALB配下のhttpdでHTTPS判定がずれる、SetEnvIfで直す

  • Apache
  • ALB
  • HTTPS

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

何が起きるか

ALBやCloudFrontのようなロードバランサー・リバースプロキシの後ろにApache(httpd)を置く構成だと、クライアント〜LB間はHTTPSでも、LB〜Apache間は素のHTTPで通信していることが多い。

この場合、Apacheやその上で動くPHPなどのアプリケーションから見ると、リクエストは常にHTTPで届いているように見える。結果として$_SERVER['HTTPS']が空になったり、フレームワーク側の「HTTPSかどうか」の判定がずれて、リダイレクトループやCookieのSecure属性周りで問題が出たりする。

Client --HTTPS--> ALB --HTTP--> Apache(httpd)

原因

LB側は元のプロトコルをX-Forwarded-Protoヘッダーに詰めて転送してくる。ALBやCloudFrontはデフォルトでこのヘッダーを付与する。

  • X-Forwarded-Proto: https … 元はHTTPSだった
  • X-Forwarded-Proto: http … 元はHTTPだった

だがApache自身はこのヘッダーの中身を見てHTTPS環境変数を自動的に書き換えたりはしない。素直にHTTPとして扱う。

対処

.htaccess(もしくはVirtualHost設定)に以下を書いておくと、X-Forwarded-ProtoがhttpsのときだけApacheのHTTPS環境変数をonにできる。

SetEnvIf X-Forwarded-Proto "https" HTTPS=on

これで$_SERVER['HTTPS']がonとして見えるようになり、PHPやフレームワーク側のHTTPS判定が正しく動くようになる。mod_rewriteの%{HTTPS}を条件に使っている場合も同様に効いてくる。

注意点

  • X-Forwarded-Protoはクライアントが直接偽装できるヘッダーなので、LBを経由しない直アクセスを許可している構成だと、この設定だけでは信頼できない。LB以外からの直接アクセスを塞ぐか、LB側で強制的にヘッダーを上書きする設定と合わせるのが安全らしい(実機で直アクセス遮断まで検証したわけではないので、そこは未確認)。
  • mod_sslが有効な環境でSSLEngine自体をonにしているわけではない。あくまでアプリケーション側から見た判定を補正しているだけで、Apache〜LB間の通信そのものがHTTPSになるわけではない。
  • Nginxの場合はfastcgi_param HTTPS $http_x_forwarded_protoのように別の書き方になる。

結論

ALBやCloudFrontの後ろにApacheを置くなら、X-Forwarded-Protoを見てHTTPS環境変数を補正する設定はほぼセットで必要になる。.htaccess一行で済むので、リダイレクトループやCookieのSecure属性がおかしいと思ったら、まずここを疑うのが早い。