プログラミング
Kcgi – C/C++向けミニマルなCGIおよびFastCGIライブラリ
Kcgi – minimal CGI and FastCGI library for C/C++ (kristaps.bsd.lv)
要約
Kcgiは、C/C++で書かれたWebアプリケーション向けのオープンソースCGIおよびFastCGIライブラリです。ミニマル、セキュア、監査可能であることを特徴としています。特筆すべきは、OS固有のサンドボックス機能(seccomp, pledge, sandbox_init, capsicum)を利用して、信頼できない入力処理を分離・保護する点です。
全文翻訳
kcgiは、C/C++ Webアプリケーション向けのオープンソースCGIおよびFastCGIライブラリです。ミニマルで、セキュアで、監査可能です。
まず、ライブラリをインストールします。次に、デプロイメントおよび使用ガイドを読みます。
以下のコードは、CGIリクエストに対するHTTPレスポンスとして「Hello, World!」を出力する例です。
#include <sys/types.h> /* size_t, ssize_t */
#include <stdarg.h> /* va_list */
#include <stddef.h> /* NULL */
#include <stdint.h> /* int64_t */
#include <kcgi.h>
int
main(void)
{
struct kreq r;
const char *page = "index";
/*
* HTTP環境をパースします。
* "index"という単一のページのみを認識し、
* 指定がない場合はデフォルトページとなります。
* (入力フィールドは検証しません。)
*/
if (khttp_parse(&r, NULL, 0, &page, 1, 0) != KCGI_OK)
return 1;
/*
* 通常、ここではメソッド(OPTIONSなど、
* method変数で定義)でスイッチし、
* 次にリクエストされたページ(page変数)でスイッチします。
* しかし、簡潔にするため、単に応答を出力します:HTTP 200。
*/
khttp_head(&r, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]);
/*
* Content-Typeをtext/plainとして一方的に表示します。
* 通常はr.mimeから設定されます。
*/
khttp_head(&r, kresps[KRESP_CONTENT_TYPE], "%s", kmimetypes[KMIME_TEXT_PLAIN]);
/* これ以上のHTTPヘッダーはありません:HTTPドキュメントボディを開始します。 */
khttp_body(&r);
/*
* ここに任意のコンテンツ(JSON, HTMLなど)を配置できます。
* 通常はMIMEタイプでスイッチします。
* しかし、ここでは指定されたリテラル文字列を配置します…
*/
khttp_puts(&r, "Hello, world!");
/* ドキュメントをフラッシュし、リソースを解放します。 */
khttp_free(&r);
return 0;
}
さらに詳しい例については、sample.c (CとCGI)、samplepp.cc (C++とCGI)、sample-fcgi.c (CとFastCGI) を参照するか、ドキュメンテーションセクションに進んでください。
kcgiは多くの機能をサポートしています:自動圧縮、検証付きの全HTTP入力操作(クエリ文字列、クッキー、ページボディ、マルチパート)の処理、認証、設定可能な出力キャッシュ、リクエストデバッグ、フォーマット済みライター(JSON, XMLなど)などです。その最も強力な差別化機能は、信頼できない入力パスを処理するためにサンドボックス化とプロセス分離を使用することです。
現在のリリース(リリースアーカイブ)
インストール
まず、kcgiが既にシステムにパッケージ化されていないか確認してください。例えば、pkg_add kcgi (OpenBSD)、pkg install kcgi (FreeBSD)、brew install kcgi (brew)、pacman -S kcgi (Arch Linux) などです。もしそうであれば、そのシステムを使用してインストールしてください。
もしパッケージ化されていない場合、kcgiはGNU/Linux (muslとglibc)、OpenBSD、NetBSD、FreeBSD、Solaris、OmniOS、Mac OS X (Mojave以降のみ!) のi386、amd64、powerpc、arm64、sparc64でビルドおよび実行されています。
kcgi.tgzをダウンロードし、kcgi.tgz.sha512でアーカイブを検証してください。リリース間の最新コードを実行するには、リポジトリはGitHubにあります。どちらの場合も、ビルドおよびインストール手順はリポジトリページで見つけることができます。
唯一のビルド時のハード依存関係は、BSD make (Linuxではbmake) とzlibです。回帰テスト(Testingを参照)を実行する場合は、libcurlも必要になります。
デプロイメント
kcgiを使用するには、CGIまたはFastCGIを実行できるWebサーバーが必要です。Apache、nginx、OpenBSDのhttpd(8)などが広く使用されており、後者2つはFastCGIネイティブまたはslowcgiラッパー経由で利用できます。
kcgiアプリケーションをコンパイルするには、パッケージ構成を使用します。リンクも同様に標準的です。
% cc `pkg-config --cflags kcgi` -c yourprog.c
% cc yourprog.o `pkg-config --libs kcgi`
適切にデプロイされたWebサーバー、例えばデフォルトのOpenBSDサーバーは、デフォルトでchroot(2)内でデプロイされます。この場合、バイナリを静的リンクするか(または共有ライブラリすべてをシャドウルートに引き込む)必要があります。
% cc -static yourprog.o `pkg-config --static --libs kcgi`
FastCGIアプリケーションは、Webサーバーによって直接起動されるか(Apacheで一般的)、または外部からソケットとkfcgi(8)が与えられるかのいずれかです(この方法はOpenBSDのhttpd(8)で標準的であり、ラッパーが取るセキュリティ上の注意のために推奨されます)。
ドキュメンテーション
kcgiのmanページ、kcgi(3)から始まるものが、公式のドキュメントソースです。以下は、すべてのmanページのリストです:
Alternatively, the following are introductory materials to the system:
これらのリソースに加えて、以下のカンファレンスセッションでkcgiが参照されています。
Dzonsons, Kristaps. Role-based Access Control in BCHS Web Applications. Proceedings of AsiaBSDCon, Tokyo, Japan, March 2018. (Slides, video.) paper.)
Dzonsons, Kristaps. Secure BSD Web Applications in C: Practical Strategies. Proceedings of AsiaBSDCon, Tokyo, Japan, March 2017. (Slides.)
Dzonsons, Kristaps. Secure BSD Web Application Development in C. Proceedings of AsiaBSDCon, Tokyo, Japan, March 2016. (Slides.)
Dzonsons, Kristaps. kcgi: securing CGI applications in C. Proceedings of AsiaBSDCon, Tokyo, Japan, March 2015. (Slides, paper.)
そして、標準の拡張に関連するものは以下の通りです。
Dzonsons, Kristaps. FastCGI Extensions for Management Control. March 2016.
実装の詳細
kcgiのCGI処理の大部分はkhttp_parse(3)にあり、HTTPリクエストを完全にパースします。アプリケーション開発者は、他のすべての関数よりも前にこの関数を呼び出す必要があります。
FastCGIの場合、この関数はkhttp_fcgi_init(3)(コンテキストを初期化)とkhttp_fcgi_parse(3)(新しいパース済みリクエストを受信)に分割されます。いずれの場合も、リクエストはkhttp_free(3)によって解放される必要があります。
すべての関数は、信頼できないネットワークデータのパースと検証を、サンドボックス化された子プロセス内で分離します。サンドボックスはプロセスが利用できる環境を制限するため、パースプロセス(またはサードパーティライブラリでの検証)での悪用可能なエラーがシステム環境に影響を与えることはありません。このパースされたデータは、ソケットを介して親プロセスに返されます。
以下の例では、HTTPパーサーと入力バリデーターが単一のHTTPリクエストを管理し、コネクションデリゲーターが新しいHTTPリクエストを受け入れて渡します。
この信頼できないパースプロセスをサンドボックス化する方法はOpenSSHに従っており、各オペレーティングシステムで特別な処理が必要です。
seccomp(2) (Linux)
これはseccomp対応のLinuxカーネルと認識されたハードウェアアーキテクチャを必要とします。setrlimit(2)による制限が補完されます。
pledge(2) (OpenBSD)
これはOpenBSD >5.8でのみ機能します。
sandbox_init(3) (Apple OSX)
これはMac OS X Leopard以降で提供される純粋な計算のためのサンドボックス化プロファイルを使用します。setrlimit(2)によるリソース制限が補完されます。
capsicum(4) (FreeBSD)
FreeBSD 10以降のケーパビリティ機能を使用します。setrlimit(2)によるリソース制限が補完されます。
検証はサンドボックス内で行われるため、検証ルーチンが環境(ファイルを開く、ネットワーク接続するなど)にアクセスしないように特別な注意が必要です。なぜなら、子プロセスはサンドボックス機能によって突然終了させられる可能性があるからです(すべてのサンドボックスがこれを行うわけではありません)。必要であれば、この種の検証はパース検証シーケンスの後に行うことができます。
コネクションデリゲーターも同様ですが、開いたソケット接続を管理し、新しいリクエストに応答する必要があるため、異なるサンドボックス化ルールがあります。
テスト
kcgiは、make regressで実行される完全に自動化されたテストフレームワークを備えています。
独自のアプリケーションをテストするには、kcgiregress(3)ライブラリを使用します。このフレームワークはミニWebサーバーとして機能し、ローカルポートでリッスンし、HTTPドキュメントを最小限のCGIリクエストに変換し、そのリクエストをkcgi CGIクライアントに渡します。
内部テストでは、libcurlを使用してテストリクエストが構築されます。
バインディングローカルポートは固定されています。回帰スイートを実行する予定がある場合は、アクセスポートを調整する必要があるかもしれません。
テストフレームワークは、GitHub Actionsによって、すべてのコミットがすべてのプラットフォームで回帰テストに合格することを確認するために使用されています。