Apache設定ファイルのSetEnv/SetEnvIf適用順番

2020年1月31日

2020年1月30日現在、ココVALUE-SERVERで使用されているapache2.2(古い)で.htaccessを使っていろいろな設定が出来る。出来るけど、その設定には適用順番があるって話(2.4でも同様)。

事の発端

SetEnv HOGE "deny"
Order Deny,Allow
Deny from env=HOGE

この.htaccessが置かれたディレクトリが見えてしまう。論より証拠がこちら

参考リンクに置いたapacheのドキュメントに従って解説を入れると、

  1. SetEnvは環境変数HOGEに値denyを設定している
  2. Orderはまず全てをAllowとした上で、Deny処理を適用後に、Allow処理を入れるという宣言
  3. Denyは環境変数HOGEが設定されていたら、全部Denyとするという意味

つまり、書かれた順番どおりに処理されたなら、この.htaccessが置かれたディレクトリでは全て403 Forbiddenになるはず」ということ。しかし200 OKで見えてしまっているわけです。

いろいろ疑い調べましたが、日本語の2.2のマニュアルには記載がありませんが、英語の2.2以降のマニュアルと、日本語の2.4以降のマニュアルに、

SetEnv はリクエスト処理の 段階の中でも遅くに実行されます。つまり SetEnvIf や RewriteCond などからは、変数がそこで設定されていることがわかりません。

https://httpd.apache.org/docs/2.4/ja/env.html#setting

という、よ~く読み漁らないと見つからない記述を見つけました。2.2の日本語版ではどれだけ読み漁っても見つかりませんけど…。

で、「それ本当なの?」「本当ならどう書けばいいの?」というのを読み解くのが今回のミッションです。

実験

そもそもSetEnv出来てるの?

SetEnvの成功例が必要です。確認できたのが、こちらの.htaccessになります。

SetEnv HOGE "deny"
Header set X-Frame-Options %{HOGE}e env=HOGE

解説

  1. 環境変数HOGEに値denyを設定する
  2. 環境変数HOGEが設定されていたら、HTTPレスポンスヘッダのX-Frame-Optionsに環境変数HOGEの内容を設定する

結果

こちらのリンク先のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
...
X-Frame-Options: deny
...

SetEnv自体は出来てますね。成功です。つまり処理順序の問題であるという可能性が高まりました。

じゃあDeny fromは出来てるの?

次はDeny fromの成功例が必要です。環境変数パターンは試せてませんが、.htaccessでAllow/Deny設定を上書き可能かどうかはApacheの設定次第なので、確認が必要ということです。確認用の.htaccessが以下です。

Order Deny,Allow
Deny from All

解説

  1. Orderはまず全てをAllowとした上で、Deny処理を適用後に、Allow処理を入れるという宣言
  2. 全てをDenyする

つまり、「この.htaccessを含むディレクトリ以下は全て403 Forbiddenになる」という設定です。

結果

こちらのリンク先のディレクトリに当該.htaccessを置いています。 辿れば分かりますが、403になります。置かれてるファイルはいつものsample.htmlです。

SetEnvIfとSetEnvの処理順序確認

記述内容の確認になります。SetEnvIfからSetEnvの結果を参照して本当にうまく動作しないかどうかを見ます。確認用.htaccessが以下になります。

SetEnv HOGE "deny"
SetEnvIf HOGE "deny" HOGECHILD=deny
Header set X-Frame-Options %{HOGECHILD}e env=HOGECHILD

解説

  1. 環境変数HOGEに値denyを設定する
  2. 環境変数HOGEの値がdenyだったら、環境変数HOGECHILDに値denyを設定する
  3. 環境変数HOGECHILDが設定されていたら、HTTPレスポンスヘッダX-Frame-Optionsに環境変数HOGECHILDの値を設定する

結果

こちらのリンク先のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
Date: Wed, 29 Jan 2020 23:38:37 GMT
Server: Apache
Last-Modified: Wed, 29 Jan 2020 21:28:41 GMT
ETag: "1581901-31-59d4e063ccc5b"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 61
Connection: close
Content-Type: text/html

X-Frame-Optionsヘッダの出力がありません。確かにうまく動作しておらず、SetEnvIfがSetEnvより処理が早い可能性が高まります。

SetEnvIfは単体なら動くの?

単体で機能するなら、処理順序で確定します。確認用.htaccessが以下になります。

SetEnvIf Remote_Addr ".*" HOGE=deny
Header set X-Frame-Options %{HOGE}e env=HOGE

解説

  1. クライアントIPアドレスRemote_Addrの値が正規表現で".*"にマッチしたら、環境変数HOGEに値denyを設定する(何でもマッチするので、必ず設定される)
  2. 環境変数HOGEが設定されていたら、HTTPレスポンスヘッダX-Frame-Optionsに環境変数HOGEの値を設定する

結果

こちらのリンク先のディレクトリに当該.htaccessを置いています。Chromeなどの開発者ツールでNetworkモニタリングしつつ、リンク先を読み込めば、HTTPプロトコルのレスポンスヘッダを見ることで分かります。

HTTP/1.1 200 OK
...
X-Frame-Options: deny
...

X-Frame-Optionsヘッダの出力されています。単体なら確かにうまく動作しており、SetEnvIfがSetEnvより処理が早いことが確定しました。

SetEnvの代わりにSetEnvIfにしてみる

最後にどうすればいいの?の回答です。.htaccessが以下になります。

SetEnvIf Remote_Addr .* HOGE=deny
Order Deny,Allow
Deny from env=HOGE

新しい要素がないので解説は省略

結果

こちらのリンク先のディレクトリに当該.htaccessを置いています。 辿れば分かりますが、403になります。置かれてるファイルはいつものsample.htmlです。

参考リンク