💻

Apache2.4で特定のURLだけアクセス制限の対象から除外する

2018/04/25に公開

一生覚えられる気がしないので自分のためにメモします。

やりたかったこと

  • サイト全体についてIP指定許可でアクセス制限
  • ただし、特定のURL(例としてここでは /public* とする)だけは制限なしでアクセス可能に
  • サイトはフレームワークを使って実装されていて、/index.php がフロントコントローラーである (←ここポイント)

/index.php がフロントコントローラーである」とは

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule .* index.php [L]
</IfModule>

こういう .htaccess が設置されている状態です。

パターン1 ❌最初に試したけど期待どおり動作しなかった例

<Location />
    Require ip xxx.xxx.xxx.xxx
</Location>

<Location /public>
    Require all granted
</Location>

これで行けるだろうと思ったら、すべてのURLが403になってしまいました。

パターン2 ❌次に試したけど期待どおり動作しなかった例

<Location />
    SetEnvIf REQUEST_URI "/public" public
    <RequireAny>
        Require env public
        Require ip xxx.xxx.xxx.xxx
    </RequireAny>
</Location>

こんな方法も試してみましたが、

  • /index.php/public* はアクセス可能
  • /public* はアクセス不可

となってしまいました。

パターン3 ⭕最終的に期待どおり動作した例

<Location />
    Require ip xxx.xxx.xxx.xxx
</Location>

<Location /public>
    Require all granted
</Location>

<Location ~ ^/index.php$>
    Require all granted
</Location>

これで(ほぼ)期待どおり動作しました。

つまり、フロントコントローラーである/index.phpにアクセス制限が掛かってしまっていたのが原因だった ということですね。

なので、パターン2の方法でも、

<Location />
    SetEnvIf REQUEST_URI "/public" public
    <RequireAny>
        Require env public
        Require ip xxx.xxx.xxx.xxx
    </RequireAny>
</Location>

<Location ~ ^/index.php$>
    Require all granted
</Location>

<Location />
    SetEnvIf REQUEST_URI "/public" public
    SetEnvIf REQUEST_URI "^/index.php$" public
    <RequireAny>
        Require env public
        Require ip xxx.xxx.xxx.xxx
    </RequireAny>
</Location>

とすれば、同様に動作します。

ちなみに

この方法だと、/index.php へのアクセスだけは無用に許可されてしまいます 😓

これを回避する方法をご存知の方いらっしゃいましたら教えていただけると嬉しいです。。(リバースプロキシで別のvhostに飛ばす、とか??)

再現用Docker環境

(せっかく作ったので)実験に使ったDocker環境を上げてあります。

https://github.com/ttskch/docker-apache2.4-test

その他雑多なメモ

<Location> は最後にマッチしたものが適用される

<Location />
    Require ip xxx.xxx.xxx.xxx
</Location>

<Location /public>
    Require all granted
</Location>

<Location ~ ^/index.php$>
    Require all granted
</Location>

は期待どおりに動作しましたが、

<Location /public>
    Require all granted
</Location>

<Location ~ ^/index.php$>
    Require all granted
</Location>

<Location />
    Require ip xxx.xxx.xxx.xxx
</Location>

だと(<Location /> を最後に移動)すべてのURLが403になりました。

REQUEST_URI にはクエリパラメータは含まれない

ので、要注意です。

https://httpd.apache.org/docs/2.4/ja/mod/mod_rewrite.html

REQUEST_URI
The path component of the requested URI, such as "/index.html". This notably excludes the query string which is available as its own variable named QUERY_STRING.

REQUEST_URI の中身を知りたいときは

Apacheが REQUEST_URI をどう認識しているのか知りたい!というときは、環境変数 REQUEST_URI を出力するLogFormatを作って、CustomLogとして出力するとよいです。

LogFormat "%{REQUEST_URI}e" request_uri
CustomLog ${APACHE_LOG_DIR}/hoge.request_uri.log request_uri

参考: https://www.adminweb.jp/apache/log/index2.html

GitHubで編集を提案

Discussion