ドキュメントを読まない輩

結論: ぐぐるな。ドキュメントに書いてあるとわかっているのになぜ google に頼る?

巷間でよく見られる、しかし Apache の配布アーカイブ一式に含まれているドキュメントをちゃんと読んでいれば起きないはずの設定ミスや、ミスではないがふしぎな設定について。

Apache のドキュメントは日本語未訳なところが一部残っているけれど、全体として非常によくまとまった情報源である。少なくとも、「このディレクティブをどう設定するとどう動くか」についてはこれに勝るドキュメントはない。しかし、ドキュメントに正しい方法が書いてあるのは確実なのに、あえて google あたりで腐った知識を仕入れてきたあげくに、それをそのまま自分の Web サイトに写して誤解の拡大再生産に努める人がいる。なんで?


<Limit> の危険

ぐぐってみると以下のような設定をしよう、と書かれていることが多い

AuthType Basic
AuthName ...
AuthUserFile ...
AuthGroupFile /dev/null
<Limit GET>
    require valid-user
</Limit>

require のかわりに order/allow/deny になってることもあるが、これも同様。

だが、特に理由がなければ、<Limit> を使う必要はない。うかつに使うと、アクセス制限したつもりですり抜けてしまう危険性がある。具体的にどんな問題があるかについてはこちらを参照のこと。

ドキュメントから抜粋。

何度でも書くが、自分が何をしようとしているか理解していなければ<Limit>の中にアクセス制限設定を書いてはいけない。さもなくば、せっかくのアクセス制限が無意味になりかねない。<Limit> を使っていいのは NCSA HTTPd または Apache 0.8 未満をいまだに使っている場合だけである。

おまけ。認証に関しては、<Limit> とは直接の関係はないが、AuthName も間違った意味で解説されることが多いディレクティブである。これはあくまで認証の領域(realm)を指示するものであって、「ブラウザの認証ダイアログに表示させる文字列」というのは副次的な効果である。日本語を使いたいとか、途中で改行したいとか、はては HTML タグを使いたいなんて質問をたまに見ることがあるが、ナンセンスである。


AddDefaultCharset none の謎

誰ですか。こんなあやしげな charset を広めたのは。

Apache をインストールしたときのままの httpd.conf では日本語で書かれたページが化けるというのはよく知られた話である。これは AddDefaultCharset ディレクティブの値がそう設定されている(デフォルト値ではない。サンプルでインストールされる httpd.conf でデフォルトと異なる値を与えている(*1))からで、解決するにはこれをいじってやればよい。だが、いじるというのは正しいのだが、どういうわけか、これを none に変えろというウソを書いたサイトがある。たとえばITmedia エンタープライズ:Linux Tips - Apache2.0でページが文字化けしてしまう(いつのまにか修正されたようだが)。ほかにもぐぐってみるとこんなにたくさん検索対象を日本語ページに限定してもたいして数が減らないので、日本でだけ蔓延してる現象らしい(が、一部輸出もされている模様)。信じられないことに、iso-8858-1 を指定する(8859 ではなく)などという荒技もあるようだ。

もっとわけわかんないのが、

AddDefaultCharset shift_jis
AddDefaultCharset EUC-JP
AddDefaultCharset noneの3つを追加。
となってるサイト。いや、ひとつでいいってば。これについては、3つのうちからひとつを選んで追加しろ、という主旨のことをわかりにくく説明をしているサイトから伝言ゲームをやっているうちに歪んでしまった誤解のように思える。ほんとうにそうかは知らないが。いずれにせよ、配布元のドキュメントを読んでいれば起きるはずのない間違いである。

じゃあ none じゃなくてどう設定するのが正しいのか。啓蒙の意図もこめて、ここでは正解は書かない。公式ドキュメントへのリンクを張るだけ。

この記述からどうして none というキーワードがわいてきたのか、ほんとうに理解できない。

いちおう補足として、AddDefaultCharset none を指定したときにどんな現象が起きるのかを以下に示す。このキーワードで google の上位にヒットしたページのうち、いかにも自宅サーバっぽいところに実際に接続して HTTP のレスポンスヘッダを見てみた。

% w3m -dump_head http://武士の情けで伏せる.no-ip.com/
HTTP/1.1 200 OK
Date: Mon, 18 Oct 2004 03:55:02 GMT
Server: Apache/2.0.40 (Red Hat Linux)
Accept-Ranges: bytes
X-Powered-By: PHP/4.2.2
Connection: close
Content-Type: text/html; charset=none

AddDefaultCharset で指定した none という文字列がそのまま charset としてくっついている。ブラウザは通常ここで指定された文字コードでページが書かれているものとして動作する。しかし none などというおかしな文字集合をブラウザが知っているはずがない。そういう場合、ブラウザはしかたないのでサーバからの応答を無視して自力で文字コードを判別ようとする。これが正しく判別されれば、文字化けは解消される。つまり、エラーリカバリのはたらかない軽度の設定ミスから、リカバリのはたらくずっとひどい設定ミスに変わり、そのおかげで文字化けが解消されたように見えるだけであって、正しい設定がされたゆえの結果ではない。こういう場合に自動判別を試みずデフォルトの文字コードとして取り扱うブラウザ(Safari など)もあり、このようなブラウザでは文字化けは解消されない。

ところで、経済の世界で履行しなくちゃいけない債務を履行しないことをデフォルトというように、本来 default とは欠席とか棄権とかを意味する単語である。in default of ... = 〜がない場合には。つまり、AddDefaultCharset というのは、「他の場所で特に設定されていないとき」に付加される文字コードである。要するに、AddDefaultCharset をいじるのではなく「他の場所」で設定することも可能である。すなわち、

AddType "text/html; charset=EUC-JP" .html
あるいは、拡張子を .html.euc-jp にして
Options +MultiViews
とか。EUC 以外でも同様に。この場合、文字コードを付加しない、というのは無理だが。


(*1) Apache 2.0.53 から "setting a site-wide default does more harm than good" という理由により httpd-std.conf から削除された(CHANGES)。


LanguagePriority の意味

文字化けの件で AddDefaultCharset について記述されているサイトの多くであわせて言及されているのが、LanguagePriority で ja を先頭にもってこい、ということ。

主に日本語のコンテンツを提供するサーバにおいて、この設定は間違ってはいない。間違ってはいないが、*文字化け解消を目的とするのであれば*、まったく無関係である。無意味である。ドキュメントを読んでもそんな記述はない。このディレクティブはそれとは異なる意図で使われるものだからだ。

主に日本語のコンテンツを提供するが、日本語以外のコンテンツも同時に提供するサーバなのであればこの設定も意味があろう。しかしそうでもなければ放っておいてもいいディレクティブである。このディレクティブを提供するモジュールの機能を考えれば無意味さもわかるというものだ。どんなときに使われるかは以下を参照のこと。

多くのサイトであたかも文字化け解消には必須のように AddDefaultCharset と LanguagePriority をセットで解説しているのは、やはりドキュメントを読まず、よそのサイトをなんとなく写してるだけなのではないかと思われる。コンテンツが日本語であることを明示したいのならば、LanguagePriority ではなく DefaultLanguageAddLanguage ディレクティブを使うのが適切だろう(ただし、文字化けとはやはり無関係)。もし万が一 LanguagePriority の設定をしたために文字化けがなおった、あるいは設定が間違っていたために文字化けしたという例があれば教えてほしい。文字化けではなく言語化けならありうるだろうが。


影の薄い ScriptAlias

Q. /cgi-bin/ 以下に HTML や画像ファイルを置いたのですが、アクセスしてもエラーになります。なぜでしょうか?

A. ScriptAlias の効いた場所に CGI 以外のファイルを置こうという発想自体が間違いです。

httpd.conf を見ないエンドユーザがこれにひっかかるのはしかたない気もする。が、自分で Apache を設定する人がこれでハマるのならば不見識もはなはだしい。自分で設定しなくてもはじめからそうなっているわけだが、おかしいと思ったら httpd.conf を眺めれば怪しそうな部分はすぐ見つかるし、それを頼りにドキュメントを読めば対処方法もすぐにわかるはずだ。google で検索するとこの症状はいろいろひっかかるが、ScriptAlias にまで言及されているところはほとんどなく、このディレクティブの影の薄さには涙を誘われる。

なぜ表示できないかというと、CGI としての実行に失敗しているからである。つまり、実行できるものならば動く。これは特に Windows で動いている Apache ではセキュリティ上の問題を招く可能性がある。

実例を挙げると、imgboard という画像アップロード CGI は、アップロードされたファイルを cgi-bin 以下のディレクトリに保存することを前提に作られているので、この問題が発生しやすい。ScriptInterpreterSource Registry の設定で、かつ「画像が表示できない」状態の imgboard に画像をアップロードしてやると、それをダウンロードすることでサーバ上で画像ファイルの拡張子に関連づけられたビューワが起動する(らしい)ので、大量にアクセスしてやれば DoS になる。また ScriptInterpreterSource Script の設定(デフォルト)だと拡張子ではなく #! を解釈するので、悪意ある CGI を .jpg などの拡張子で偽装してアップロードしてやると、それをダウンロードすることでサーバをクラックできる(だろう)。ドキュメントには前者の場合の危険性は警告されているが、後者の例には触れられていないので注意のこと。わしは Windows で Apache をいじることはしないので確認してないけどドキュメントを信ずれば(そういう態度もどうかと思うが:-))そのように動作するはず。なお、UNIX はレジストリがないので ScriptInterpreterSource Script 相当だが、通常アップロードしただけでは実行パーミッションがないのでこのような攻撃はできない。


SetEnvIf ... Lilith の不思議

間違っているわけではないのだが、よそのサイトの設定をそのままコピーしてるだけと思われる例をもうひとつ。

HTTP のリクエストヘッダによってアクセス制限をかける場合(典型例としては Referer による参照元制限)、(1)SetEnvIf で適当な環境変数をセットし、(2)その環境変数がセットされていればアクセス拒否する、という2段構えの設定になる。それは正しいのだが、そのセットする環境変数の名前が、なぜか Lilith とされることが多い

環境変数名は任意のものでいいので間違ってはいないし、ちゃんと望んだとおりに動作する。だが、いったいどこから Lilith という文字列が出てきたのか。この用途で誰もが自然に思い浮かぶ単語ではないと思うのだが。

参考までに、Apache の配布ドキュメントの例では local_referal という環境変数名になっている。

なお、Referer はそもそも偽造がかんたんにできるし、プライバシーなどの理由からわざと送出しないようにしたり書き換えたりすることもあるので、これによるアクセス制限は完全ではない(それどころか副作用になることもある)のだが、まあ、その是非についてはここでは深く触れない。

ところで、この SetEnvIf によるアクセス制限を Accept-Language ヘッダに対しておこない、クライアントの言語チェックをするということもよくおこなわれているようだ。しかし、403 Forbidden を返してしまうこの方法よりも、言語ネゴシエーションの機能を使って 406 Not Acceptable を返すが適切だろう。具体的には、httpd.conf か .htaccess で

Options +MultiViews
# Apache 2 では以下も追加
# ForceLanguagePriority Prefer	# または None (Fallback を含まないようにする)
# 以下は任意で
# ErrorDocument 406 ...
としてコンテンツネゴシエーションを有効にした上で、ファイル名の hoge.html を hoge.html.ja に変える(HTML からリンクする URL は hoge.html のままにしておく)。これにより、hoge.html へのアクセスのうち、Accept-Language に ja が含まれるリクエストには hoge.html.ja が返され、A-L に ja が含まれないクライアントには 406 Not Acceptable のエラーを返すことができる(406 のエラー画面に hoge.html.ja へのリンクが含まれてしまうので、ErrorDocument でエラー表示をカスタマイズしておいた方がいいだろう)。


google などの検索エンジンなどにより、間違った設定の拡大再生産がおこなわれているとしか思えない。また、誤解をまねきやすい説明がついていたり、ある特定の目的でのみ正しい設定だったりと、かならずしも間違いではない設定も、検索エンジンを介した伝言ゲームを繰り返すうちに明白に間違った設定に変化していってるのではないだろうか。

google に頼るばかりじゃなくて、付属のドキュメントをちゃんと読もう。あるかどうかわからないものを google で探すよりも、あるとわかっているものを付属ドキュメントから探す方がずっとラクだと思うんだけど。「マニュアル人間」「マニュアル世代」のようなネガティブイメージの言葉もあるけど、この言葉で問題にされているのはマニュアルに書いてあることしかできないこと、応用力のないことである。マニュアルを読みさえしないのは「マニュアル人間」にすら及ばない。

なお、このページ自体も、google にひっかかる真偽の定かでないあやしげなページのひとつである。ここに書かれていることを鵜呑みにせず、自分でドキュメントを調べなおしてほしい。


もどる
<y@maya.st>