突然Apache 2.x系のお話。Apache 2.xでは入力されるデータと出力するデータに対し、複数のフィルタ処理を行うことができる。POSTメソッドで送信されるリクエストボディをInput Filterで検査する方法。
すべてのプログラムをフィルタにする
というのは UNIXという考え方 で語られるUNIXの定理の一つですが、Apache 1.3.x時代はリクエストボディにフィルタ処理を施すためには、なんともこれ本当にやってイイの?的な手法が必要だった。しかしApache 2.x系では入力に関しても任意の数のフィルタ処理を挟み込むことができるので、再利用性を維持し小さく単機能のモジュールの組み合わせで必要な機能を実装することができます。
Input Filterの実装
リクエストボディに対するフィルタ処理はInput Filterで行います。その登録はApache 2.x系の各ハンドラと同様にRegister Hooks関数を使ってフィルタ関数に名前を付けて登録します。 #include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"
#include "http_log.h"
static int bodycheck_filter(ap_filter_t *f, apr_bucket_brigade *bb,
ap_input_mode_t mode, apr_read_type_e block,
apr_off_t readbytes)
{
apr_status_t rv;
apr_bucket *b;
const char *body;
apr_size_t body_len;
rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
if (rv != APR_SUCCESS)
return rv;
APR_BRIGADE_FOREACH(b, bb) {
if (!APR_BUCKET_IS_EOS(b)) {
rv = apr_bucket_read(b, &body, &body_len, APR_BLOCK_READ);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
"apr_bucket_read() failed");
return rv;
}
/* 長さbody_lenの入力値 bodyをチェックする */
/* 不正な入力の場合は return HTTP_FORBIDDEN; など適当なerrorを返す */
}
}
return rv;
}
static void register_hooks(apr_pool_t *p)
{
/* Input Filter "BODYCHECK" を登録 */
ap_register_input_filter("BODYCHECK", bodycheck_filter,
NULL, AP_FTYPE_RESOURCE);
}
/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA bodycheck_filter_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
register_hooks /* register hooks */
};
多分Apache 1.3.x系になれ親しんだ人はAPR_BRIGADE_FOREACH()?apr_bucket_read()?なにそれ、って感じではないかと思うのですが、まぁ2.x系ではこういう作法ってことで。お陰で1.3.xではできないことも色々できますのよ。Input Filterの設定
で上記のモジュールをビルドしインストールし、httpd.confへ次のような記述を追加すれば /path/to/cgi 以下へのリクエストに際してBODYCHECKフィルタとして登録されたbodycheck_filter()関数が実行され、リクエストボディのチェックを行うことができるようになります。 <Directory /path/to/cgi>
SetInputFilter BODYCHECK
</Directory>
さぁ、ウィルスチェックなりワレ物対策なり、入力値のvalidateなりお好きなように!