ReverseProxyでredirect時にhttp<->httpsが変わってしまう問題

| コメント(1)

Apacheを使ってReverseProxyしていて、フロント(クライアント)からのアクセスをhttpsで、バックエンドをhttpでやっているようなケースでの問題。mod_proxyのドキュメント通りに、おおむね以下のような設定を書いているハズ。

<VirtualHost *:443>
  (...snip...)
  ProxyPass /bugzilla http://192.168.1.3/bugzilla
  ProxyPassReverse /bugzilla http://192.168.1.3/bugzilla
  (...snip...)
</VirtualHost>

ProxyPassReverseは、バックエンドがLocationヘッダでリダイレクトしようとするような場合に、pathをReverseProxyっぽく(クライアントの都合のいいように)書き換えるオプション。このとき、Locationが相対パスなら特に問題ないものの、絶対パス(特にhttp://がある)場合に問題になる。つまり、ReverseProxyはpathは書き換えるもののプロトコルはhttpのままとなり、クライアントはhttpsからhttpにリダイレクトされてしまう。たぶんhttp/httpsの関係が逆でも同じことが起こるハズ。

これを解決する方法はググるとおおむね2つ見つかる。1つめは「もう一度リダイレクトする」ことで、つまり、クライアントがhttpでアクセスしたらhttpsにアクセスするようにしておく。何度もリダイレクトするのがムダなものの、負荷さえ気にしなければそれほど悪くもない。ただ、デフォルトポート(httpを80, httpsを433)にやっているならこういう対処も可能だけど、ポート番号を変更している場合、ポート番号はそのままにプロトコルだけ切り替わってしまい、httpsで待ち受けるポートにhttpでアクセスされることになってしまうので、この方法は使えない。

もう1つが「X-FORWARDED-PROTO」を使う方法で、ReverseProxyがバックエンドにリクエストするとき「X_FORWARDED_PROTO: 'https'」を付加することでバックエンドのアプリに指示を出してバックエンドのアプリに適切なLocation: を吐かせるようにする。

<VirtualHost *:443>
  (...snip...)
  RequestHeader set X_FORWARDED_PROTO 'https'
  (...snip...)
</VirtualHost>

ただ、「X-FORWARDED-PROTO」はあくまでアプリに指示をするだけのもので、Ruby on Rails だとこれを解釈してくれるものの、bugzillaなどそうでないアプリの方が圧倒的に多い気がする。ReverseProxyがnginxの場合だと「proxy_redirect http:// https://;」なんて方法があるようだけど、Apacheだとあまり適切な設定項目がない。いろいろ悩んだ結果、力業であることを承知で下記のように対処。

<VirtualHost *:443>
  (...snip...)
  Header edit Location ^http https
  ProxyPass /bugzilla http://192.168.1.3/bugzilla
  ProxyPassReverse /bugzilla http://192.168.1.3/bugzilla
  (...snip...)
</VirtualHost>

HeaderディレクティブについてはApacheのmod_headersの英語ドキュメントを参照。なぜか日本語版には Header editが書いてない。日本語のドキュメントだけ見てたときは「Apache 2.4からか?」と勘違いしてしまった。

コメント(1)

「Header edit Location ^http: https:」の方が事故が少ない気がした。

このブログ記事について

このページは、らるるが2015年5月23日 22:20に書いたブログ記事です。

ひとつ前のブログ記事は「Movable Typeが遅すぎる」です。

次のブログ記事は「「SQLアンチパターン」読んだ」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 5.2.13