ApacheのOrderディレクティブの解釈

(2007.11.11)
一部加筆(2007.11.17)

 ApacheでIPアドレスに基づいてアクセス制限を掛けたいとき、httpd.confや.htaccessにAllow fromやDeny fromディレクティブを記述して設定する。それはいいのだが、それらでのIPアドレスの指定を終えた後、Orderディレクティブをどう書こうかと考えたときに筆者はしょっちゅう間違えるのである。
 Apacheのマニュアルには次のように書いてある。

Order ディレクティブはデフォルトのアクセスの状態と Allow ディレクティブと Deny ディレクティブが評価される順番を制御します。 Ordering は以下のどれかです。

Deny,Allow
Deny ディレクティブが Allow ディレクティブの前に評価されます。 アクセスはデフォルトで許可されます。Deny ディレクティブに合わないか、Allow ディレクティブに合うクライアントはアクセスを許可されます。
Allow,Deny
Allow ディレクティブが Deny ディレクティブの前に評価されます。 アクセスはデフォルトで拒否されます。Allow ディレクティブに合わないか、Deny ディレクティブに合うクライアントはアクセスを拒否されます。

 例えば、192.168.0.1からのみアクセスできるように設定したいとしよう。このマニュアルの記述を斜め読みして、なるほど、Allowで192.168.0.1を許可してから、他はDenyで全て拒否すればいいのだな。などと考え、

Order Allow,Deny
Allow from 192.168.0.1
Deny from all

と書いて一件落着。ということならいいのだが、そうは問屋が卸さない。これだと全てのクライアントが拒否されてしまうのである。正しくは

Order Deny,Allow
Allow from 192.168.0.1
Deny from all

でなければならない(なお、AllowとDenyディレクティブの行の出現順序には意味はない)。

 この記事をここまで読んで、こんな間違いはしたことがないと思った読者はこれ以上読み進める必要はない。むしろ混乱するのでこれ以上読まない方がいいかも知れない。
 しかし多くのネットワーク管理者は上に挙げたような間違いをしがちなのではなかろうか。というのは、ルータでフィルタに使うアクセス制御リスト(ACL)などは、上で説明したような考え方で動作するのが普通だからである。
 すなわち、ACLの場合、クライアントからアクセスが来たら、許可のエントリ(ApacheでのAllow fromに相当)にせよ、拒否のエントリ(同Deny from)にせよ、そのホストのアドレスを順々にそれらと引き比べていき、マッチしたところで処理は確定、それより後のエントリは見ない。とすれば、上の例だとAllowが先に評価されるのだから、Allow from 192.168.0.1のエントリで許可に確定。アクセスが可能になるはずなのである。
 ところがApacheの発想はそうではない。Apacheの動作は概念的には次のようになる。Order Allow,Denyの場合でいうと、まずApacheは設定ファイルの読み込み時に0.0.0.0から255.255.255.255までのすべてのIPアドレスの一覧表のようなものを内部的に作り、それをまずデフォルトであるDenyの色(ここでは赤としよう)で全て塗りつぶす。次に、Allowディレクティブで指定されたIPアドレスについてのみAllowの色(ここでは青としよう)で上書きする。しかるのちに、今度はDeny fromで指定されたIPアドレスについてのみDenyの色、すなわち赤でさらに上書きする。このような準備を行った上で、実際にクライアントからアクセスがあったときは、その一覧表の上のそのIPアドレスの箇所の色を見、赤なら拒否、青なら許可する。
 このように、評価が前のものは後のもので上書きされてしまうのである。

 ACLの発想が染みついていてこの発想には馴染めないという人にはいい覚え方がある。単純に、Orderディレクティブでは実際の評価順とは逆順に指定すると覚えればいいのである。このように考えると、ACL式に「マッチしたら確定」と考えても結論的には正しくなる。

コンピュータ関連記事一覧へ