Apache Web サーバーの設定メモ

作成日:2003.10.08
修正日:2004.06.03


このページは、 日記に書き貯めてきた 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 が有効である。

例: 以下のようにアクセスを特徴づけ別々のファイルにロギングすることにする。

ログ出力のカスタマイズを行う CustomLogディレクティブ は、 HTTP リクエスト毎に環境変数が設定されている(またはされていない)ことを 判断して出力することができる。

方針に合わせて環境変数を設定してやればよい。
条件の生成には SetEnvIfディレクティブを使う。 条件に合わせて環境変数を設定することができる。

SetEnvIf attribute regex env-variable[=value] [env-variable[=value]] ...

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 を使おう。

参考: Apache mod_setenvif モジュール

アクセスを分類してロギング(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 して機能を拡張した。
追加したのは SetEnvIfAllSetEnvIfEither のディレクティブ。

SetEnvIfAll name  value  expr1 [expr2 [expr3 [...]]]
SetEnvIfEither name  value  expr1 [expr2 [expr3 [...]]]

SetEnvIfAllexpr(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-resourcemax-resource は数値か max というキーワードを指定可能。 max を指定した場合には、OS の許すリソースの最大値が設定される。 CGI プロセスのリソースが soft-resource を越えた場合、Apache から SIGKILL シグナルが送られ強制停止させられる。

max-resource は指定できる soft-resource の上限を決めるパラメータ。 RLimitCPU / RLimitMEM / RLimitNPROC は <Directory> の階層構造中でオーバーライドすることが可能だが、基本的には制限を厳しくする(値を小さくする)方向にしか指定できない。 ただし、root の権限で実行中は上限を緩める(値を大きくする)指定も可能。

コメント

コメントを書き込む

TOP    掲示板    戻る
Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp