
コンピューティングにおいて、Common Gateway Interface(CGI )とは、 Webサーバーが外部プログラムを実行してHTTPまたはHTTPSのユーザー要求を処理できるようにするインターフェース仕様である。
このようなプログラムはスクリプト言語で記述されることが多く、一般的にCGIスクリプトと呼ばれますが、コンパイルされたプログラムが含まれる場合もあります。[ 1 ]
典型的な使用例として、Web ユーザーがCGI を使用する Web ページ上のWeb フォームを送信する場合が挙げられます。フォームのデータは、 CGI スクリプトを示すURLを含むHTTP リクエストでWeb サーバーに送信されます。Web サーバーは、フォームデータを渡して、新しいコンピュータ プロセスで CGI スクリプトを起動します。CGI スクリプトは、通常HTMLの形式で出力をWeb サーバーに渡し、サーバーはそれをブラウザのリクエストに対する応答としてブラウザに返します。[ 2 ]
1990年代初頭に開発されたCGIは、ウェブページをインタラクティブにするための最も初期の一般的な手法でした。しかし、クライアントからのリクエストがあるたびにCGIスクリプトを別のプロセスで実行する必要があったため、さまざまな代替手段が開発されました。
1993 年、国立スーパーコンピューティングアプリケーションセンター(NCSA) チームは、www-talk メーリングリストでコマンドライン実行可能ファイルを呼び出すための仕様を作成しました。[ 3 ] [ 4 ] [ 5 ]他の Web サーバー開発者がこれを採用し、それ以来、Web サーバーの標準となっています。1997年 11 月に、ケン・コアが議長を務める作業グループが、NCSA の CGI の定義をより正式に定義するために活動を開始しました。[ 6 ]この作業の結果、CGI バージョン 1.1 を規定するRFC 3875が作成されました。RFC で具体的に言及されている貢献者は次のとおりです。[ 2 ]
歴史的に、CGI プログラムはC プログラミング言語を使用して記述されることが多かった。RFC 3875「共通ゲートウェイインターフェイス (CGI)」は、環境変数が「 C ライブラリルーチン getenv() または変数 environによってアクセスされる」と述べることで、 C を使用した CGI を部分的に定義している[ 2 ]。
CGIという名称は、ウェブ黎明期にウェブマスターたちがデータベースなどの既存の情報システムをウェブサーバーに接続しようとした際に生まれたものです。CGIプログラムはサーバー上で実行され、ウェブサーバーと既存の情報システム間の共通の「ゲートウェイ」として機能しました。
従来、Webサーバーにはドキュメントコレクションとして指定されたディレクトリがあり、これはサーバーに接続されたWebブラウザーに送信できるファイルのセットです。[ 7 ]例えば、Webサーバーの完全修飾ドメイン名www.example.comがで、そのドキュメントコレクションが/usr/local/apache/htdocs/ローカルファイルシステム(ドキュメントルートhttp://www.example.com/index.html)のに保存されている場合、Webサーバーはのリクエストに対して、ファイルが存在する場合はそのコピーをブラウザーに送信して応答します/usr/local/apache/htdocs/index.html。
動的に生成されるページの場合、サーバーソフトウェアはリクエストを別のプログラムに委ね、その結果をリクエスト元のクライアント(通常は、エンドユーザーにページを表示するWebブラウザ)に中継することがあります。
このようなプログラムでは通常、クエリ文字列やクッキーなど、リクエストとともにいくつかの追加情報を指定する必要があります。逆に、スクリプトは応答を返す際に、リクエストのHTTPステータス、ドキュメントの内容(利用可能な場合)、ドキュメントの種類(HTML、PDF、プレーンテキストなど)といった、HTTPがリクエストへの応答に必要とするすべての情報を提供しなければなりません。
当初、ブラウザ、通信相手のHTTPサーバー、そしてサーバー上でデータを処理して最終的にブラウザに結果を返すスクリプトの間でデータを交換するための標準化された方法は存在しませんでした。そのため、異なるHTTPサーバー間で互換性の問題が生じ、スクリプトの移植性が損なわれていました。
この問題が認識されたことで、データ交換の方法が規定され、CGIが開発されました。CGI仕様に準拠したサーバーソフトウェアによって呼び出されるWebページ生成プログラムは、C言語などのスクリプト言語以外の言語で記述されている場合でも、CGIスクリプトと呼ばれます。
CGI仕様は急速に採用され、 Apache、Microsoft IIS、そして(拡張機能付きの)Node.jsベースのサーバーなど、多くの著名なHTTPサーバーパッケージで引き続きサポートされています。
CGIスクリプトの初期の用途の一つは、フォームの処理でした。HTMLの初期の頃、HTMLフォームには通常「action」属性と「submit」ボタンが設けられていました。submitボタンが押されると、「action」属性で指定されたURIがサーバーに送信され、フォームのデータはクエリ文字列として送信されました。「action」属性にCGIスクリプトが指定されている場合は、そのCGIスクリプトが実行され、スクリプトによってHTMLページが生成されました。
CGI をサポートする Web サーバーは、CGI スクリプトへの参照として提供するURLを解釈するように構成できます。一般的な慣習として、ディレクトリツリーのベースにcgi-bin/ディレクトリを作成し、このディレクトリ内のすべての実行可能ファイル (セキュリティ上の理由から他のディレクトリは除く) を CGI スクリプトとして扱います。Web ブラウザーが CGI ディレクトリ内のファイル (例: ) を指す URL を要求するとhttp://example.com/cgi-bin/printenv.pl/with/additional/path?and=a&query=string、HTTP サーバーは単にそのファイル ( /usr/local/apache/htdocs/cgi-bin/printenv.pl) を Web ブラウザーに送信するのではなく、指定されたスクリプトを実行し、スクリプトの出力を Web ブラウザーに渡します。つまり、スクリプトが標準出力に送信するものはすべて、Web サーバーを起動したターミナル ウィンドウに表示されるのではなく、Web クライアントに渡されます。もう 1 つの一般的な慣習は、ファイル名拡張子を使用することです。たとえば、CGI スクリプトに一貫して拡張子 が付けられている場合.cgi、Web サーバーは、そのようなすべてのファイルを CGI スクリプトとして解釈するように構成できます。これは便利で、多くのパッケージ化されたスクリプトで必要とされますが、リモート ユーザーが適切な拡張子を持つ実行可能コードをアップロードできる場合、サーバーが攻撃を受ける可能性があります。
CGI 仕様では、リクエストとともに渡される追加情報がスクリプトに渡される方法が定義されています。Web サーバーは、渡された環境変数のサブセットを作成し、HTTP 環境に関連する詳細を追加します。たとえば、スクリプト名 (この例では ) の直後にスラッシュと追加のディレクトリ名が URL に追加されている場合、そのパスはスクリプトが呼び出される前に環境変数/with/additional/pathに格納されます。パラメータがHTTP GETリクエスト (URL に疑問符が追加され、その後に param=value のペアが続く。この例では ) を介してスクリプトに送信される場合、それらのパラメータはスクリプトが呼び出される前に環境変数に格納されます。HTTP POSTリクエストを介して送信されるフォーム パラメータなどのリクエストHTTP メッセージ本文は、スクリプトの標準入力に渡されます。スクリプトは、これらの環境変数または標準入力からのデータを読み取り、Web ブラウザーのリクエストに適応することができます。[ 8 ]PATH_INFO?and=a&query=stringQUERY_STRING
CGIは、ユーザーからの入力情報を処理し、適切な出力を生成するためによく使用されます。CGIプログラムの例としては、Wikiを実装するプログラムが挙げられます。ユーザーエージェントがエントリ名を要求すると、WebサーバーはCGIプログラムを実行します。CGIプログラムは、そのエントリのページのソース(存在する場合)を取得し、それをHTMLに変換して、結果を出力します。WebサーバーはCGIプログラムからの出力を受け取り、ユーザーエージェントに送信します。次に、ユーザーエージェントが「ページを編集」ボタンをクリックすると、CGIプログラムはHTMLtextareaまたはその他の編集コントロールにページのコンテンツを入力します。最後に、ユーザーエージェントが「ページを公開」ボタンをクリックすると、CGIプログラムは更新されたHTMLをそのエントリのページのソースに変換して保存します。
CGI プログラムは、デフォルトでは Web サーバーのセキュリティ コンテキストで実行されます。CGI が初めて導入されたとき、NCSA、Apache、CERN の Web サーバーのリファレンス ディストリビューションには、シェル スクリプトや C プログラムで新しい CGI を利用する方法を示すためのサンプル スクリプトが多数提供されました。そのようなサンプル スクリプトの 1 つは、シンプルな電話帳を実装した PHF という CGI プログラムでした。
当時、他の多くのスクリプトと同様に、このスクリプトは `.` 関数を使用していましたescape_shell_cmd()。この関数は、ユーザー入力から取得した引数をサニタイズし、Web サーバーのセキュリティ コンテキストで実行される Unix シェルに渡すはずでした。しかし、このスクリプトはすべての入力を正しくサニタイズしておらず、シェルに新しい行が渡されることを許容していたため、複数のコマンドが実行される可能性がありました。これらのコマンドの結果は、Web サーバーのセキュリティ コンテキストで許可されている場合、攻撃者は悪意のあるコマンドを実行することができました。
これは、Web ユーザーからのサニタイズされていないデータによって Web サーバー上でコードが実行される可能性がある、コード インジェクションと呼ばれる新しいタイプの Web ベースの攻撃の最初の広範な例でした。サンプル コードはデフォルトでインストールされていたため、攻撃は広範囲に及び、1996 年初頭に多数のセキュリティ勧告につながりました。[ 9 ]
Bashの「Shellshock」脆弱性は、環境変数に注入されたデータの実行を可能にするものであり、これはCGIがHTTPヘッダーをプログラムに利用可能にするために使用するメカニズムと全く同じです。したがって、CGIプログラムとして使用されるBashスクリプトは、リモートコード実行の脆弱性の影響を受ける可能性があります。[ 10 ]
Webサーバーは、受信したHTTPリクエストごとに、それを処理するための新しいCGIプロセスを作成し、HTTPリクエストの処理が完了するとそのCGIプロセスを破棄します。プロセスの作成と破棄は、特にCGIプログラムが仮想マシンによって解釈される必要がある場合、プロセスの出力生成という実際の作業よりも多くのCPU時間とメモリリソースを消費する可能性があります。HTTPリクエストの数が多い場合、結果として生じるワークロードはWebサーバーをすぐに過負荷状態に陥らせる可能性があります。
CGIプロセスの作成と破棄に伴う計算オーバーヘッドは、以下の手法によって削減できます。
mod_perl:、mod_phpおよびmod_python)、NSAPIプラグイン、ISAPIプラグインなどのWebサーバー拡張機能は、Webサーバー内でホストされ、複数のリクエストを処理する長時間実行されるアプリケーションプロセスを可能にします。mod_wsgiで定義され、 Apache モジュール、Gunicorn Web サーバー (Nginx と Django などのスクリプト/フレームワークの間)、UWSGIなど、さまざまな方法で実装されています。あらゆるWebアプリケーションの最適な構成は、アプリケーション固有の詳細、トラフィック量、トランザクションの複雑さによって異なります。これらのトレードオフを分析し、特定のタスクと時間予算に最適な実装を決定する必要があります。Webフレームワークは、 CGIスクリプトを使用してユーザーエージェントとやり取りする代替手段を提供します。