それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Apacheのフィルタ機能mod_ext_filerを使ってみる。

apache 2 のフィルタ機能をちょっと試してみた

今のところ、ナニに使うかを決めずに調べていたので、用途はイメージつかないけど、デバッグが面倒なPHPなどに渡す文字列や、出力がXMLでどうしようもないものをJSON化するに、既存のコードに手を加えず、リクエストフィルタで何とかする際には使えそう。認証に使えるかと思ったけど、inputではリダイレクトが出来ないみたい。

mod_ext_filter で任意のコマンドを挟み込む

mod_filterとmod_ext_filter で任意のコマンド(RubyスクリプトPHP/Python)をフィルタプログラムとして利用できる。UNIXのパイプみたいに使える。

inputFilter( rubyなど ) -> phpとかの処理 -> outputFilterChain (rubyなど)

と、リクエストとレスポンスの両方に任意のプログラムを実行することが可能になる。

mod_ext_filter を適用してみた

以下のディレクトリにフィルタを適用してみた。動作をチェックしたのはOSXバンドルのApache2.4

~/takuya/filter/index.php

フィルタの設定

フィルタの定義と適用設定をhttpd.conf と httpd.conf からincludeされた.conf でおこなった。

なお、定義はconfのみ、適用設定は.htaccessでも行ける模様。

作った設定は次の通り

ExtFilterDefine testInput \
    cmd="/usr/local/apache/bin/inputfilter.rb" \
    mode=input
ExtFilterDefine testOutput \
    cmd="/usr/local/apache/bin/outfilter.rb" \
    mode=output
<Directory "/Users/takuya/Sites/filter">
  SetInputFilter testInput
  SetOutputFilter testOutput
</Directory>

ここでは、ExtFilterを定義して、それぞれを、Directiveでinput/output に適用するように記述した。

フィルタプログラム

フィルタのプログラムは実行できて標準出入力さえできればなんでもいける。

/usr/local/apache/bin/inputfilter.rb に書いたのは次の通り

#!/usr/bin/env ruby
#

require 'logger'


puts :filter

fname = "/usr/local/apache/log.txt"
log = Logger.new fname
log.info("called")
log.info(ENV.keys.join("\n") )
log.info(ARGF.readlines.join("\n"))

input フィルタが起動したら、Loggerにリクエストの内容をキャプチャしてINFOログを書くようにした。

実行結果

ヘッダの情報にもアクセスできる。POST情報は、Inputの本文として入力されてくる。通常のCGIと何ら変わらない。

I, [2015-10-19T18:35:03.200748 #97833]  INFO -- : called
I, [2015-10-19T18:35:03.200850 #97833]  INFO -- : SCRIPT_URL
SCRIPT_URI
HTTP_HOST
HTTP_USER_AGENT
HTTP_ACCEPT
HTTP_COOKIE
PATH
DYLD_LIBRARY_PATH
SERVER_SIGNATURE
SERVER_SOFTWARE
SERVER_NAME
SERVER_ADDR
SERVER_PORT
REMOTE_ADDR
DOCUMENT_ROOT
REQUEST_SCHEME
CONTEXT_PREFIX
CONTEXT_DOCUMENT_ROOT
SERVER_ADMIN
SCRIPT_FILENAME
REMOTE_PORT
GATEWAY_INTERFACE
SERVER_PROTOCOL
REQUEST_METHOD
QUERY_STRING
REQUEST_URI
SCRIPT_NAME
DOCUMENT_URI
DOCUMENT_PATH_INFO
__CF_USER_TEXT_ENCODING
I, [2015-10-19T18:35:03.200891 #97833]  INFO -- :

ヘッダ情報はENVつまり、環境変数として取得できる。

input の書換え

入力されたPOSTデータを書き換えてみよう。

curl で aaa=bbb をPOSTする。ただし、フォイル側では、一切のリクエストを全部処分する。

inputフィルタ

#!/usr/bin/env ruby
puts "name=value"

実行結果。index.phpで var_dump($_POST)をしたらこんな感じ。

curl localhost/~takuya/filter/ -d aaa=bbb
Hello World
array(1) {
  ["name"]=>
  string(6) "value
"
}

見事に送信したPOSTデータは書き換えられた。

ヘッダ情報にアクセスはできても、inputフィルタではリクエストは確定してるので、ヘッダ書換は無理っぽいね。

input で処理を挟み込むならrewrite map のほうが良さそう。

環境変数として来たリクエストデータ(GET・COOKIEQUERY_STRING)を書き換える方法は見つからなかったし思いつかなった。

output フィルタ

出力側のフィルタでは、ブラウザに送るデータが取れるのでやりたい放題できる。

インプットフィルタは 攻撃検出には使えそう

リクエストのログを取れるので実験場には有益かもしれない。けど、Apacheのカスタムログでやるだろうし。うーん使い所が。。。

POSTデータの書き換えは不正な入力値を消すには使えそうだけど、フィルタでやるよりPHPやRack側でやるほうが便利だろうし。

フィルタ処理といえば認証に使えば便利だとおもうけど、出来ないし。ちょっと微妙な機能だった。

フレームワーク中ですら、フィルタチェインが大量にあると発狂したし、フィルタってやっぱり使い所難しい

ある程度フィルタかけ始めると、mod_security でいいやってなるしな

参考資料

mod_ext_filter - Apache HTTP サーバ バージョン 2.2

フィルタ - Apache HTTP サーバ バージョン 2.2