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・COOKIE・QUERY_STRING)を書き換える方法は見つからなかったし思いつかなった。
output フィルタ
出力側のフィルタでは、ブラウザに送るデータが取れるのでやりたい放題できる。
インプットフィルタは 攻撃検出には使えそう
リクエストのログを取れるので実験場には有益かもしれない。けど、Apacheのカスタムログでやるだろうし。うーん使い所が。。。
POSTデータの書き換えは不正な入力値を消すには使えそうだけど、フィルタでやるよりPHPやRack側でやるほうが便利だろうし。
フィルタ処理といえば認証に使えば便利だとおもうけど、出来ないし。ちょっと微妙な機能だった。
フレームワーク中ですら、フィルタチェインが大量にあると発狂したし、フィルタってやっぱり使い所難しい
ある程度フィルタかけ始めると、mod_security でいいやってなるしな