より良い CGI プログラム作成について


目次

[戻る]


はじめに - 本当に CGI は必要か?

CGI (Common Gateway Interface)を使うと色々できるのですが,サーバーへの負荷を考えて作成された CGI プログラムは少ないように思われます. そこで,サーバーへの負荷を減らす方法について述べたいと思います.

まず,自分の行いたいことが CGI 以外の方法でできないかを考えてみましょう. もしも,CGI を使わなくても済むのなら,CGI を使わないという選択は正しいものです.

しかし,CGI を使わなければ無理だということになると,他の人の迷惑にならないためにもサーバーへの負荷をかけないプログラムを作成することを考えましょう.

また,セキュリティにも十分注意しましょう. CGI を使って何かできるということは非常に危険をともないます. 単純な悪戯では済まなくてファイルを消されるかもしれません. サーバーに負荷がかかって停止してしまうかもしれません. あるいは,他のサーバーに迷惑をかけるかもしれません.

[目次に戻る]


簡単にできること - ファイルとして保存

掲示板システムなどで,内容を表示する時にも CGI プログラムを呼び出すものが多数あります. これは非常に無駄なことであり,サーバーへの負荷という観点から一番よくないことです.

よく考えてみましょう. 掲示板に書き込む人よりも,掲示板を読んでいるだけの人の方が多いはずです. つまり,書き込む時だけ CGI プログラムを呼び出し,書かれた内容を HTML ファイルとして保存し,読みたい人には HTML ファイルを読んでもらうようにしておけば,CGI プログラムはほとんど呼び出されません.

なるべく,CGI を使わないようにすることがサーバーへの負荷を減らす最もよい方法です.

[目次に戻る]


応答ヘッダ

CGI の動作を把握しておくために応答ヘッダについて簡単に説明します.

クライアントは,サーバーから送られてくるデータをどのようにして判断し表示しているのでしょうか? 実は,送り返されてくるデータの先頭には,サーバーが付けた応答ヘッダがあります. これにより,クライアントはデータがどのようなものかを判断できるようになっています. CGI でも適切な応答ヘッダを付けてやることが必要です.

応答ヘッダの詳細を知りたければ,RFC 2616CGI 入門CGI プログラムの改良案などを参照してください.

サーバーが付けてくれる応答ヘッダの例を見てみましょう.

HTTP/1.1 200 OK
Date: Sat, 16 Dec 2000 04:29:13 GMT
Server: Apache/1.3.14 (Unix) mod_ssl/2.7.1 OpenSSL/0.9.5a
Last-Modified: Fri, 20 Oct 2000 08:09:48 GMT
Accept-Ranges: bytes
Content-Length: 2630
Content-Type: text/html

HTTPのバージョン(HTTP/1.1)と状態コード(200)と理由フレーズ(OK),日付(Date),サーバーソフトウェアの名前(Server),最終更新日時(Last-Modified),データ単位(Accept-Ranges),送られるデータの大きさ(Content-Length),送られるデータの種類(Content-Type)というようになっています. ヘッダのあとに,空行が1行存在し,その後ろに送られるデータが続きます.

例えば,大きな画像データなどを表示する際,クライアントによってはどの程度取得できたのかが表示されますが,このような応答ヘッダをもとに判断しているわけです.

このように送られてくるデータに関する情報は応答ヘッダに含まれています.

[目次に戻る]


CGI の基本的な仕組

市販されている書籍の中には,CGI がどのような仕組で動いているのかを解説していないものがあります. CGI の基本的な仕組を知らずにプログラムは作成できませんし危険です.

通常の CGI プロセス

通常の CGI プロセスは以下のように処理が進みます.

  1. クライアントがサーバーに要求を送る.

  2. サーバーは要求に応じて CGI プログラムを起動する. クライアントからの要求内容は,環境変数 (GET) や標準入力 (POST) などによって CGI プログラムに渡される.

  3. CGI プログラムが処理した結果は,標準出力に掃き出される.

  4. サーバーは標準出力を受け取り,内容に応じた応答ヘッダを生成し,クライアントに結果を送る.

このように,サーバーがする仕事量は単にファイルを転送するよりも多くなります. 仮に,Perl で書かれた CGI プログラムが同時に100プロセスも動くなら,たいていのサーバーは処理が非常に重くなるでしょう.

通常の CGI に付けられる応答ヘッダ

通常の CGI でも同じようにサーバーが応答ヘッダを付けてくれますが,サーバーには送り出すデータの種類が分かりません. (通常,サーバーはデータの種類を拡張子により判断していますが,CGI ではどのようなデータが送られるか分からないからです.) そこで,Content-Type ヘッダはプログラム内で宣言することが必要になります.

例えば,Perl を用いて作成した CGI プログラムで,プログラムの処理が成功(200 OK)し,HTML (text/html) を文字コード ISO-2022-JP で送るならば,次のように応答ヘッダを生成すればよいでしょう.

print "Content-Type: text/html; charset=ISO-2022-JP¥n"
print "¥n"
…HTML…

[目次に戻る]


NPH の利用

意外に知られていないようですが,Apache などのサーバーでは NPH (Non-Parsed Headers) が利用できます. サーバーが応答ヘッダをつける処理をしなくて済むのでサーバーへの負荷が減ります. ファイル名を nph-hogehoge.cgi のように先頭を nph- で始まるファイル名にしておくと,NPH スクリプトとして処理されます.

NPH のプロセス

NPH は以下のように処理が進みます.

  1. クライアントがサーバーに要求を送る.

  2. サーバーは要求に応じて CGI プログラムを起動する. クライアントからの要求内容は,環境変数(GET)や標準入力(POST)などによって CGI プログラムに渡される.

  3. CGI プログラムの処理した結果は,標準出力に掃き出される.

  4. サーバーは標準出力をそのままクライアントに送る.

このように,NPH ではサーバーが応答ヘッダを付けないため,サーバーへの負荷が減ります. その代わり,CGI プログラムが応答ヘッダを作り出す必要があります.

NPH に付けられる応答ヘッダ

NPH の場合,サーバーは一切のヘッダを付けずに処理結果を送り出すため,CGI プログラムが正しいヘッダを付けてやらねばなりません.

例えば,Perl を用いて作成した CGI プログラムで,プログラムの処理が成功(200 OK)し,HTML (text/html) を文字コード ISO-2022-JP で送るならば,次のような応答ヘッダを送ればよいでしょう.

print "HTTP/1.1 200 OK¥n"
print "Status: 200 OK¥n"
print "Content-Type: text/html; charset=ISO-2022-JP¥n"
print "¥n"

[追記] 正確には,改行コードを LF ではなくて,CR + LF にする必要があります. もっとも,LF だけでも動く場合が多いです.

Perl を用いて作成した CGI プログラムで,要求を拒否(403 Forbidden)し,エラーメッセージをテキスト (text/plain) で文字コード EUC-JP で送るならば,次のような応答ヘッダになるでしょう.

print "HTTP/1.1 403 Forbidden¥n"
print "Status: 403 Forbidden¥n"
print "Content-Type: text/plain; charset=EUC-JP¥n"
print "¥n"

[目次に戻る]


時間切れの処理

CGI プログラムが何らかの理由で無限ループに入り込んでしまったり,処理が終わらなくなってしまったりする可能性があります. これはサーバーへの負荷を著しく高めることになるので,適当な時間が経過したら CGI プログラムを終了するようにしておくことが大切です.

例えば,Perl なら,シグナルを用いて次のような処理で可能です.

#プログラムの先頭で実行,10秒で終了する
alarm(10);
$SIG{'ALRM'} = 'kill_process';
…
#サブルーチン
sub kill_process {
  …適切な終了処理…
  exit;
}

[目次に戻る]


セキュリティの確保 - SuExec の利用

たいていのサーバーは,nobody 権限などで動いています. このため,CGI プログラムが書き込みできるようにするためには,ファイルのパーミッションを chmod 666 hogehoge,ディレクトリのパーミッションを chmod 777 hogehoge などのようにしておかなければなりません.

もしも,悪意を持ったローカルユーザーがいる場合,他のユーザーのファイルを消すことができ,ファイルの内容を覗くこともできます. また,プログラムにミスがあった場合には意図しなくても他のユーザーの CGI プログラムやデータを消してしまう危険性があります.

Apacheには,SuExec という仕組があります. これは,CGI の実行ユーザーを,実際のファイル所有者にできる仕組(setuid と同じ)です. つまり,書き込みたいファイルのパーミッションを 600 とできますし,CGI プログラム自体のパーミッションも 700 でよいのです. パーミッションの設定が 777 のようになっていると CGI プログラムを動作させないようにもできます.

このため,他のユーザーにファイルを覗かれたり,消されてしまうことを防げます. また,CGI プログラムにミスがあっても所有者のファイルだけで被害が済むことにもなります.(サーバーへの負荷は別問題です.)

CGI を動かせるサーバーを構築する必要性があれば,SuExec を使わない手はありません.

その他の注意点としては,

[目次に戻る]


参考文献


[目次に戻る] | [戻る]