このページは、 日記に書き貯めてきた Apache Web サーバーの設定メモを まとめたもの。
メニュー
HTTP ヘッダーの Content-type フィールド | ... | HTTP で返すファイルの正しい MIME タイプ設定方法 |
URL Rewriting | ... | mod_rewrite モジュールを使い URL へのアクセスを別の URL へ誘導 |
カスタムエラーレスポンス | ... | エラーに対応した HTML を表示 |
アクセスを分類してロギング(1) | ... | SetEnvIf モジュールを使いアクセスログの分類を行う |
アクセスを分類してロギング(2) | ... | SetEnvIf モジュールを改造して もっと複雑な条件を記述できるようにする |
CGI プログラムのリソースを制限する | ... | CGI プログラムの暴走に備えて、 CGI プログラムが使用できるリソースに制限を設ける。 |
HTTP ヘッダーの Content-type フィールド
Microsoft Word や Excel のデータも Web 上に置いておけば、
Internet Explorer(IE) なら
http://hoge.moge/~nminoru/page.xls
のように開くと
ファイルを保存するかそのまま開くかのダイアログが出る。
しかし、
Netscape Navigator(NN) で .doc で .xls を見ようとすると、
アプリケーションのデータをそのまま文字テキストとして開いて、
文字化けした画面が表示される。
これは Apache が認識できないデータ形式に対して
HTTP の "Context-type: text/plain" を返すのが原因のようだ。
これを防ぐには拡張子で MIME タイプの設定を行う。
手っ取り早くは、
個人の .htaccess で以下を設定する。
AddType "application/vnd.ms-excel" xls AddType "application/vnd.ms-word" doc AddType "application/vnd.ms-powerpoint" ppt
同じことは IE でも起きているはずだが、
.xls を読みこめば Excel を開こうとする。
MIME ヘッダーなど無視して
ファイルの拡張子を見ているのかしらん?
ついでに
.htaccess で
自分の書いた HTML の文字符号化スキームを
charset 使って指定しておこう。
HTML の文字符号化スキームは
META タグの charset パラメタ ではなく、
MIME header 中で charset を使って指定するのが
正しい(参考1を参照)。
MIME header 中の charset は
Apache の設定ファイル中でも指定できるが、
どのような言語・コードを使うかはユーザーに
よって異なるから .htaccess を置いて
各自設定するのがよい。
以下の設定では .html はデフォルトでは ISO-2022-JP になる。
それ以外の設定が使いたい場合には、
.jis、.sjis、.euc を使いわける。
AddType "text/html; charset=iso-2022-jp" html AddType "text/html; charset=iso-2022-jp" jis AddType "text/html; charset=Shift_JIS" sjis AddType "text/html; charset=EUC-JP" euc
設定の確認を行いたい時には、 wget を -S オプション付きで使うと便利。
> wget -S http://www.mtl.t.u-tokyo.ac.jp/~nminoru/diary/2002-11.html --21:32:58-- http://www.mtl.t.u-tokyo.ac.jp/%7Enminoru/diary/2002-11.html => `2002-11.html' Resolving www.mtl.t.u-tokyo.ac.jp... done. Connecting to ***.***.**.jp[**.**.**.**]:3128... connected. Proxy request sent, awaiting response... 1 HTTP/1.1 200 OK 2 Date: Wed, 27 Nov 2002 12:32:58 GMT 3 Server: Apache/1.3.26 (Unix) 4 Content-Type: text/html; charset=iso-2022-jp
参考:
村田氏
charsetパラメタの勧め: HTMLにおける文字符号化スキームの明示方法
URL Rewriting
Apache Web サーバの mod_rewrite モジュールは、
URL rewwriting 機能を提供する。
これは、
ある URL へのアクセスを別の URL へ誘導してしまう機能。
この機能を使うと
古い URL へのアクセスを新しい URL へ
自動的に転送させたりすることができる。
もう少し詳しく言うと Apache Web サーバは、
誘導元 URL へのアクセスがあった場合に
302(Moved Temporarily) のステータスを返し、
HTTP レスポンスの Location に誘導先 URL を載せて返す。
Web ブラウザはステータスと Location を解釈し、
新しい URL へ移動するという寸法。
例:
とりあえず方々にある自分のページを、
大学の Web に誘導するため http.conf に以下の行を追加。
RewriteEngine on RewriteCond %{REMOTE_ADDR} !^10\..+$ RewriteRule ^/~(nminoru.+) http://www.mtl.t.u-tokyo.ac.jp/~$1 [R,L]
参考:
Module mod_rewrite URL Rewriting Engine
Apache 1.3 URL Rewriting Guide
カスタムエラーレスポンス
Apache Web サーバで、
特定のディレクトリの下でエラーとなった場合に
応答メッセージを返すやり方がある。
応答は、
ローカルまたは外部の URL を返す、
単純なメッセージを表示する、
CGI を起動するなどの方法が取れる。
下は、カスタムエラーレスポンスを設定した http.conf の例。
<Directory /home/www/html/hoge/cgi-bin> ErrorDocument 401 http://www.hoge.mog/err401.html # 認証に失敗した場合 ErrorDocument 403 /home/www/html/hoge/err403.html # ホスト制限に失敗した場合 ErrorDocument 404 "404 Not Found URL" # URL が見つからない場合 ErrorDocument 500 /cgi-bin/error.cgi # 内部エラーが発生した場合 </Directory>
参考:
・カスタムエラーレスポンス
・ErrorDocument directive
アクセスを分類してロギング(1)
Apache Web サーバーはデフォルトでは access_log という名前の
ログファイルに 1 アクセス 1 行づつのログを残して行く。
だが、
コンピューターワームの攻撃が頻発する状況だと
access_log は脹れあがって行く。
そこで、
本当のアクセスとワームと判断されるアクセスなど、
アクセスを特徴づけて別々にログ管理したい。
このような場合、
SetEnvIf モジュールを用いた CustomLog が有効である。
例: 以下のようにアクセスを特徴づけ別々のファイルにロギングすることにする。
- Nimda などの明らかに攻撃を目標としたアクセスを worm_log に保存。
- 画像ファイルはログには残さない。
- グローバルアドレスからのアクセスを access_log に、
プライベートアドレス(10.*.*.*)からのアクセスを local_log に保存。
ログ出力のカスタマイズを行う CustomLogディレクティブ は、 HTTP リクエスト毎に環境変数が設定されている(またはされていない)ことを 判断して出力することができる。
方針に合わせて環境変数を設定してやればよい。
条件の生成には SetEnvIfディレクティブを使う。
条件に合わせて環境変数を設定することができる。
SetEnvIf attribute regex env-variable[=value] [env-variable[=value]] ...
- attribute には Request_URI や Remote_Addr などの HTTP リクエストのヘッダーフィールドのを指定できる他、 他の SetEnvIf(または SetEnvIfNoCase)で定義した環境変数が使える。 ただし、他のディレクティブ(SetEnvなど)で設定した環境変数はダメ。
- regexには、attribute の内容とマッチングさせるための正規表現を記述する。
- env-variableには設定した変更したい環境変数を列挙する。 指定方法は var (環境変数をただ定義)、!var (環境変数の定義を取り消す)、 var=value (環境変数に値を定義する)の 3 種類がある。
http.conf の内容は以下になった。
SetEnvIf Remote_Addr \. dont_local_log SetEnvIf Remote_Addr ^10\. dont_access_log !dont_local_log # SetEnvIf Request_URI "default\.ida|null\.ida|root\.exe|cmd\.exe" worm dont_local_log dont_access_log SetEnvIfNoCase Request_URI "ndefault\.ida|null\.ida|root\.exe|cmd\.exe" worm dont_local_log dont_access_log SetEnvIf Request_URI "\.(gif)|\.(xbm)|\.(png)" dont_local_log dont_access_log CustomLog logs/worm_log combined env=worm CustomLog logs/local_log combined env=!dont_local_log CustomLog logs/access_log combined env=!dont_access_log
Windows/IIS ではスクリプト名を大文字・小文字区別せずに指定できるようなので、default.ida は DEFAULT.IDA と入力されるかもしれない。
SetEnvIfCase
の代わりに SetEnvIfNoCase
を使おう。
アクセスを分類してロギング(2)
アクセスを分類してロギング(1) の方法は、2003年8月から急増した Nachi ワームのアクセスパターンを捉えることができない。
Nachi ワームは "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)" という User Agent フィールドを持ち、"/" を "HTTP/1.1" で GET してくるという特徴がある。
しかし、SetEnvIf
ディレクティブと CustomLog
ディレクティブだけでは OR 条件を作れるが AND 条件が作れないため、この条件にマッチするパターンを捉えることができないのだ。
そこで SetEnvIf
を提供している mod_setenvif
を hack して機能を拡張した。
追加したのは SetEnvIfAll
と SetEnvIfEither
のディレクティブ。
SetEnvIfAll name value expr1 [expr2 [expr3 [...]]] SetEnvIfEither name value expr1 [expr2 [expr3 [...]]]
SetEnvIfAll
は expr(n) の条件が全部 成立した場合に name という名前の変数を定義し、その値を value にセットする。value は定数・定数文字列である必要がある。
逆に SetEnvIfAll
は条件うちどれかが成立していれば変数をセットする。
条件部分である expr(n) には変数名を書いて、その変数が定義されている場合の条件を書くことができる。 変数名の頭の前に "!" を付けたものも書けて、この場合 変数が定義されていない場合に条件が成立する。 変数の値をチェックする機能はない(SetEnvIf を使えば間接的にできるから)。
この機能を使うと以下のように http.conf が書けるようになってログを分類できるようになる。
# 10.0.0.0/24 の IP はローカルとみなす。 SetEnvIf Remote_Addr "^10\." local_site_access # 画像ファイルの識別 SetEnvIf Request_URI "\.(jpg)|\.(gif)|\.(xbm)|\.(png)" image_file # default.ida、root.exe、cmd.exe を含 URL に含むアクセスはワーム SetEnvIf Request_URI "default\.ida|root\.exe|cmd\.exe" worm # Nachi ワーム対策 3 つの条件を列挙 SetEnvIf Request_URI "^/$" nachi1 SetEnvIf Request_Protocol "^HTTP/1.1" nachi2 BrowserMatch "^Mozilla/4\.0 \(compatible; MSIE 5\.5; Windows 98\)" nachi3 # nachi1、nachi2、nachi3 がすべて定義されていれば worm を定義してその値を 1 にする SetEnvIfAll worm 1 nachi1 nachi2 nachi3 # 画像ファイルではなく(!image_file)、ワームでもない(!worm) アクセスを分類 SetEnvIfAll output_access_log 1 !local_site_access !image_file !worm SetEnvIfAll output_local_log 1 local_site_access !image_file !worm # 条件に応じて出力する CustomLog logs/worm_log combined env=worm CustomLog logs/local_log combined env=output_local_log CustomLog logs/access_log combined env=output_access_log
mod_setenvif.c
をハックしたパッチをここ においておく。
このパッチは Apache 1.3.28 の src/modules/standard/mod_setenvif.c に
適用するためのものだが、mod_setenvif.c はあまりバージョンアップを受けていないモジュールなので、他のバージョンでもうまくいくかもしれない。
Vine Linux 2.6 (x86) / Apache 1.3.27 で確認。
(apache_1.3.28.tar.gz をどこからか入手しておく) > tar xzvf apache_1.3.28.tar.gz > cp apache_1.3.28/src/modules/standard/mod_setenvif.c . > patch mod_setenvif.c < mod_setenvif.c.patch (mod_setenvif の コンパイル) > apxs -c mod_setenvif.c (mod_setenvif.so ができたのでこれを入れ替え。モジュールのあるディレクトリは適当に読みかえること) > su # mv /usr/lib/apache/mod_setenvif.so /usr/lib/apache/mod_setenvif.so.orig # cp mod_setenvif.so /usr/lib/apache/mod_setenvif.so
自分の必要な部分しか実装していないし、十分なテストはしていなのでバグがあるかも。
分かっている範囲では Directory ディレクティブを使った多層的な設定にはちゃんと対応していない。
CGI プログラムのリソースを制限する
CGI プログラム(または SSI プログラム)が無制限にリソースを消費しないようにリミットを設けることができる。 設定できるのは以下の項目。
Directive 制限項目 RLimitCPU CGI プログラムあたりの使用可能な CPU 時間を秒数で制限。 RLimitMEM CGI プログラムが使用可能なメモリをバイトサイズで制限。 RLimitNPROC CGI プログラム等の子プロセスをいくつまで fork できるかを指定する。 ユーザーあたりのプロセス数で指定。
この directive は httpd.conf の任意の階層に指定できる。 指定方法は1オペレータと、2オペレータのどちらか。
directive soft-resource [max-resource]
soft-resource と max-resource は数値か max というキーワードを指定可能。 max を指定した場合には、OS の許すリソースの最大値が設定される。 CGI プロセスのリソースが soft-resource を越えた場合、Apache から SIGKILL シグナルが送られ強制停止させられる。
max-resource は指定できる soft-resource の上限を決めるパラメータ。 RLimitCPU / RLimitMEM / RLimitNPROC は <Directory> の階層構造中でオーバーライドすることが可能だが、基本的には制限を厳しくする(値を小さくする)方向にしか指定できない。 ただし、root の権限で実行中は上限を緩める(値を大きくする)指定も可能。