Guardian@JUMPERZ.NET

| | コメント(7) | トラックバック(1)

・Guardian@JUMPERZ.NET - Open Source Web Application Firewall
http://guardian.jumperz.net/index.html

リバースプロキシとして動作する HTTP サーバです。
サーバ側で使うもの。
パターンにマッチしたリクエスト、レスポンスに対して、ロッギング、切断、コマンド実行などが出来ます。

Apache専用の「mod_secury」に似ているらしい。
(mod_securyを触った事ないので・・・)

Javaで書かれています。
配布されているjarファイルの中にはコードが含まれています。

HTTP/HTTPS対応。
HTTPSで動作した場合、「Guardian@JUMPERZ.NET」←→「WEBサーバ」間はHTTPな通信になります。

・ユーザーズマニュアル日本語版 (Guardian@JUMPERZ.NET)
http://guardian.jumperz.net/manual/ja/body.html

・Rule Database
http://guardian.jumperz.net/index.html?i=004
新しいルールが追加されていくようです。
時々確認しましょう?

「jumperz_net.jar」ファイルのバージョン 071 を使ってみました。

中の人の「金床」さんが別のエントリに書き込みしてくれたので、記念エントリ。(違)

やりたい事

最近、このblogでスパムコメントがうるさいです。
ある程度はIPアドレス制限で防いでます。
どの辺の帯域から多く来るかも分かってきました。

でも、(公開)PROXYをかませば、あちこちから送ってこれます。
ブロックしてないIPから短期間にspam書き込みされたら、spamですぐに一杯になってしまいます。

spamは大体、ロボット(プログラム)で同じ文面を書き込んでいるみたいなので、その文面を登録しておいてブロックしたいなぁと。

  • WEBサーバ(IIS)と同一マシン上で「Guardian@JUMPERZ.NET」を動かす。(IPアドレス=「192.168.0.10」)
  • HTTPのみの接続とする(今回はHTTPSはなし)。
  • 特定の文字列を含むリクエストがPOSTされた場合、そのリクエストをブロックする。

インストール

以下からダウンロードします。

・Download (Guardian@JUMPERZ.NET - Open Source Web Application Firewall)
http://guardian.jumperz.net/index.html?i=003

「jumperz_net_071.jar」をダウンロードして、「C:\Guardian@JUMPERZNET\」に置きます。

以下を実行します。

C:\> java -classpath %CLASSPATH%;"C:\Guardian@JUMPERZNET\jumperz_net_071.jar" net.jumperz.app.MGuardian.MGuardian
Usage: java net.jumperz.app.MGuardian.MGuardian CONFIG_DIR

「Usage:」の行が出ればOK。
動く事を確認したら「C:\Guardian@JUMPERZNET\jumperz_net_071.jar」をCLASSPATH環境変数に登録しておくと良いでしょう。

また、Windowsの場合、以下の場所にコピーしてしまうのもよさ気。
J2SE SDK(JDK)が入ってるなら、「C:\j2sdk1.4.x\jre\lib\ext」。
J2SE JREの場合は「C:\Program Files\Java\j2re1.4.2_05\lib\ext」。
(バージョンは適当に読みかえてください。)
この場合はCLASSPATHを通す必要がありません。

C:\> java net.jumperz.app.MGuardian.MGuardian

以下のExceptionが出たら、jarファイルが見つかってません。
CLASSPATHとjarファイルのある場所を確認しましょう。

Exception in thread "main" java.lang.NoClassDefFoundError: net/jumperz/app/MGuardian/MGuardian

簡単な動作確認まで

「guardian_conf.tar.gz」をダウンロードして、「C:\Guardian@JUMPERZNET\」に解凍します。
これらが設定ファイルです。

● 「control」ファイル

まず、「Guardian@JUMPERZ.NET」の主要なパラメータを記述する「control」ファイルを編集します。

targetHost=localhost
targetPort=8080
replaceHostField=false
logFileName=C:\\Guardian@JUMPERZNET\\log\\guardian.log
sessionLogDirName=C:\\Guardian@JUMPERZNET\\log\\guardian
limitRequestHeader=false
limitResponseHeader=false
threadCount=35
requestHeaderTimeOut=10
requestBodyTimeOut=3600
maxConnectCount=20
urlDecodingCharset=SJIS
commandInterval=1
maxQueueCount=0
  • 「targetHost」を編集します。
    「Guardian@JUMPERZ.NET」からみたWEBサーバのホスト名(IPアドレス)を指定します。
  • 「targetPort」を編集します。
    WEBサーバが待ち受けてるポートを指定します。
  • 「logFileName」「sessionLogDirName」を編集します。
    「C:\Guardian@JUMPERZNET\log\」というフォルダを作成し、そこにログを保存するようにしました。
  • 「urlDecodingCharset」を編集します。
    WEBサイトで表示される(=リクエストに使用する?)エンコーディングを指定すればいいのかしら?

    ・サポートされているエンコーディング
    http://java.sun.com/j2se/1.4/ja/docs/ja/guide/intl/encoding.doc.html
    文字コードはこの辺を参考に設定すればいいかな?

同一マシンでWEBサーバと「Guardian@JUMPERZ.NET」の待ち受けポートを同じにすると(例えば、両方80)、「Guardian@JUMPERZ.NET」起動時に「既に使ってるからBINDできないよ」とこんなExceptionが出てしまいました。

java.net.BindException: Address already in use: JVM_Bind
        at java.net.PlainSocketImpl.socketBind(Native Method)
        at java.net.PlainSocketImpl.bind(Unknown Source)
        at java.net.ServerSocket.bind(Unknown Source)
        at java.net.ServerSocket.(Unknown Source)
        at net.jumperz.net.MMultiAcceptor.getServerSocket(MMultiAcceptor.java:122) 
        at net.jumperz.net.MMultiAcceptor.execute(MMultiAcceptor.java:43)
        at net.jumperz.util.MWorkerThread.run(MWorkerThread.java:46)
Wed Oct 20 17:55:10 JST 2004 : maxThreadCount::4
java.lang.InterruptedException: sleep interrupted
        at java.lang.Thread.sleep(Native Method)
        at net.jumperz.util.MTimer.execute(MTimer.java:39)
        at net.jumperz.util.MWorkerThread.run(MWorkerThread.java:46)

そこで、WEBサーバの設定を変更して、8080で待ち受けるようにします。
また、「control」ファイルの「targetPort」は8080にしました。
こうした場合、運用の時には、何らかの方法でlocalhost以外からWEBサーバの8080へのアクセスを遮断した方がいいでしょう。

WEBサーバ側で上手く設定すれば、両方ともポート80で待てるのかな?(バーチャルホストチックに?)
マシンに2つ以上IPアドレスをふっててもよさげ。
例2 本番稼働用構成(1ホスト HTTPSなし)」のようにしたいんだけどなぁ?

● 「listeningSocket」ファイル

次に、「Guardian@JUMPERZ.NET」がクライアントからの接続を受け付けるソケットを設定します。「listeningSocket」ファイルを編集します。
HTTPだけなので、こんなもん。

<listen>
protocol=HTTP
port=80
host=192.168.0.10
</listen>

● 「rule」ファイル

次に、ルールを決める「ruleファイル」を編集します。

まず、簡単なルールを作成して動作確認をします。
もとの「rule」ファイルのバックアップを取り、「id=GID9」のルール部分だけ抜き出して保存します。少し編集します。

var %req% "none"
 
<rule>
id=GID9
revision=1
name=BufferOverflow(URI)
type=requestUri
pattern=.{10}
condition=match
case_sensitive=no
log=yes
action=none
command=%req%
</rule>

元のルールでは300文字以上のURI HTTPリクエストを受け付けた時、ロッギングするというものでした。試験のために、10文字以上でログをとることにします。

● 起動

では、起動してみます。
設定ファイルを保存してあるパス (今回の例では「C:\Guardian@JUMPERZNET」) を指定して、起動します。

C:\> java -classpath %CLASSPATH%;"C:\Guardian@JUMPERZNET\jumperz_net_071.jar" net.jumperz.app.MGuardian.MGuardian C:\\Guardian@JUMPERZNET
Wed Oct 20 12:50:07 JST 2004 : targetPort=8080
targetHost=localhost
replaceHostField=false
logFileName=C:\Guardian@JUMPERZNET\log\guardian.log
sessionLogDirName=C:\Guardian@JUMPERZNET\log\guardian
limitRequestHeader=false
limitResponseHeader=false
threadCount=35
requestHeaderTimeOut=10
requestBodyTimeOut=3600
maxConnectionCount=35
additionalResponseHeaderMap={Server=Guardian@JUMPERZ.NET}
additionalRequestHeaderMap={X-Client-Addr=%addr, X-Protocol=%protocol}
requestFilter=null
responseFilter=null
allowedAddressList=[]
acceptorList=[class net.jumperz.net.MMultiAcceptor/192.168.0.10:80]
urlDecodingCharset=SJIS
commandInterval=1
maxQueueCount=0
 
Wed Oct 20 17:50:08 JST 2004 : Guardian@JUMPERZ.NET started.
Wed Oct 20 17:50:08 JST 2004 : maxThreadCount::1
Wed Oct 20 17:50:08 JST 2004 : maxThreadCount::2
Wed Oct 20 17:50:08 JST 2004 : maxThreadCount::3
Wed Oct 20 17:50:08 JST 2004 : maxThreadCount::4
Wed Oct 20 17:50:08 JST 2004 : maxThreadCount::5

この状態で、URLが10文字以上のページにアクセスします。

「192.168.0.11」から「http://192.168.0.10/test/test.html」にアクセスしてみました。
コマンドプロンプトにログが表示され、指定したフォルダにログが出力されれば成功です。

Wed Oct 20 18:09:56 JST 2004 : Alert:192.168.0.11:3483:GID9:1:BufferOverflow(URI
):1098245396264_3483
Wed Oct 20 18:09:56 JST 2004 : 192.168.0.11:3483 192.168.0.10:80 192.168.0.10 HT
TP GET /test/test.html HTTP/1.1 304
Wed Oct 20 18:10:07 JST 2004 : 192.168.0.11:3483 Session timed out.

ちなみに、「rule」の「action」を「block」にしておくと、コマンドプロンプトに次の様に表示されます。
HTTPリクエストに対して、FINを投げ返してるようです。

Wed Oct 20 18:18:19 JST 2004 : Alert:192.168.0.10:1664:GID9:1:BufferOverflow(URI
):1098245899408_1664
Wed Oct 20 18:18:19 JST 2004 : 192.168.0.10:1664 192.168.0.10:80 192.168.0.10 HT
TP GET /test/test.html HTTP/1.1 blocked_by_rule/GID9:1:BufferOverflow(URI)

● 終了

もう一つコマンドプロンプトを開いて、以下の様に入力します。

C:\> java -classpath %CLASSPATH%;"C:\Guardian@JUMPERZNET\jumperz_net_071.jar" net.jumperz.util.shutdown.MShutdownClient "C:\\Guardian@JUMPERZNET\\shutdown"

起動していたコマンドプロンプトに以下の様に表示され終了します。

Wed Oct 20 18:13:12 JST 2004 : shutdown password confirmed.
java.net.SocketException: socket closed
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.PlainSocketImpl.accept(Unknown Source)
        at java.net.ServerSocket.implAccept(Unknown Source)
        at java.net.ServerSocket.accept(Unknown Source)

このExceptionは、終了する時にわざとthrowしてるのかなぁ?エラー?
バージョン 071 では、正しい動作。今後修正されるかも。(金床さんのコメントより。)

「CTRL+C」で終了させても良いかな?(後処理が出来ない?)

これで、一応、動作の確認は完了です。

ちなみに、shutdown系の設定ファイルは「shutdown」ファイルです。
少しいじってみました。
「Guardian@JUMPERZ.NET」を起動してる状態で、「shutdown」ファイルの「password」を書き換えます。

password=changeMe
↓
password=changeYou

で、さっきと同様に別コマンドプロンプトからシャットダウンするために、「net.jumperz.util.shutdown.MShutdownClient」を実行します。そうすると、

Wed Oct 20 23:40:11 JST 2004 : incorrect password : changeYou

となって、シャットダウンできません。
起動する時とシャットダウンする時で、パスワードが同じならいいという事っぽいです。
「net.jumperz.util.shutdown.MShutdownClient」を実行した時にパスワードを手で入力するわけではない模様。

特定の文字列がPOSTされたらブロックする

● まずは簡単に

では、目的の「特定の文字列がPOSTされたらブロックする」ルールを作成します。
分かりやすいように、他のルールは全部消して、「rule」ファイルに以下を追加します。

<rule>
id=SPM1
revision=1
name=BlockCommentSpam1(post)
type=requestBody
pattern=BLOCK_SHITENE
condition=match
case_sensitive=no
log=yes
action=block
command=none
</rule>

「Guardian@JUMPERZ.NET」を再起動します。

実際にリクエストしてみて、ブロックされればOKです。

Wed Oct 20 18:17:46 JST 2004 : Alert:192.168.0.11:3071:SPM1:1:BlockCommentSpam1(
post):1098260266873_3071
Wed Oct 20 18:17:46 JST 2004 : 192.168.0.11:3071 192.168.0.10:80 192.168.0.10 HT
TP POST /test/post.asp HTTP/1.1 blocked_by_rule/SPM1:1:BlockCommentSpam1(post)

● 特定の日本語がPOSTされたらブロックしたい

「rule」ファイルに以下を追加します。

<rule>
id=SPM2
revision=1
name=BlockCommentSpam2(post)
type=decodedRequestBody
pattern=あいうえお
condition=match
case_sensitive=no
log=yes
action=block
command=none
</rule>

「type」に「decodedRequestBody」を指定すると、デコードするはず。。
なんだけど、「あいうえお」ってPOSTしてもスルーしちゃう??

type=decodedRequestBody
pattern=%82%A0%82%A2%82%A4%82%A6%82%A8

とすると、「あいうえお」と「%82%A0%82%A2%82%A4%82%A6%82%A8」はブロックされます。

type=requestBody
pattern=%82%A0%82%A2%82%A4%82%A6%82%A8

とすると、「あいうえお」だけブロックされます。

てことは、、、?
「control」ファイルで指定した「urlDecodingCharset」がいけないのかなぁ?

MDecodedRequestBodyRule::matches( MHttpRequest request, MResultCache resultCache )で、
リクエストに「%」「%u」「%U」が含まれていたら「MUnicodeUrlDecoder::decode( target )」で、
含まれていなかったら「URLDecoder::decode( target, MAbstractRequestRule.CHARSET )」でデコードしてるっぽいから、前者になるじゃん・・・?
てことは???(゜-。)???

どうしようかな?

●ログ

ウェブサーバーのログに記録されるIPアドレスが全て同じ値になってしまう」の件ですが、IISではカスタムヘッダをログに記録出来ないと思うので「X-Client-Addr」は使えなさそうですね?
IPアドレスはWEBサーバーのログと一緒に残しておきたいなぁ。
ハードル高め。

●自動起動

どうやって起動するのがいいんだろう?

「タスク」で起動時に実行する。
サービス化する
スタートアップに入れておく(ログオンしないといけないし
手で毎回実行する・・・(え?
 :

色々ありますが、良い方法はあるかなぁ?

(2004/10/21 追記 ここから)
● 「decodedRequestBody」にした時の動作

「decodedRequestBody」にした時の「pattern」を解釈する仕組みは、こうなってるみたいです。

  1. リクエストボディが正規表現のパターンにマッチしないかチェック。
  2. マッチしていなかったら、リクエストボディをデコードして、その文字列が正規表現のパターンにマッチしていないかチェック。
  3. 少なくともどちらか一方にマッチしていたらマッチした時の処理(ログとったりブロックしたりコマンド実行したり)をする。

「rule」ファイルの一部を以下の様に設定します。

type=decodedRequestBody
pattern=1

これで「こ」をポストすると、リクエストボディは「%82%B1」となります。
最後の「1」が1回目のマッチングでマッチします。
予期しない動作かも?
正しい動作。
「type=decodedRequestBody」の時は2度マッチングをとってる事を意識して設定する事。
(2004/10/21 追記 ここまで)

サポート

メーリングリストでのサポートを行っているそうです。

・Mailing List (Guardian@JUMPERZ.NET - Open Source Web Application Firewall)
http://guardian.jumperz.net/index.html?i=010

分からない事あったら、そこで聞けって感じですね。
こっそりMLにsubscribeしてみました。(日本語の方)
アーカイブはWEBで公開されてませんか?・・・と、更に質問・・・m(_._)m (誰に?

トラックバック(1)

このブログ記事を参照しているブログ一覧: Guardian@JUMPERZ.NET

このブログ記事に対するトラックバックURL: http://kinshachi.ddo.jp/mt/mt-tb.cgi/355

» RSSリーダー(PukiWiki/TrackBack 0.1)~のトラックバック

RSS コンピュータ系blog † 2004-10-20 Guardian@JUMPERZ.NET 2004-10-16 古いエントリの変更履歴 (2004/10) 2004-10-09 PrivBar AuthDiag Microsoft Product Support's Reporting Tools 2004-10-02 GDI+ 検出ツール GrepSidebar 2004-09-29 古いエント... 続きを読む

コメント(7)

金床 :

試して頂きまして大変ありがとうございます。
色々参考になりますが、無事に起動・動作したようでほっとしてます(笑。

ルールファイルですが、マルチバイト文字を直接記述するということを全く想定していませんでした(笑)。
まさか「あいうえお」が来るとは…。ということで、ちょっとこの場合の動作は未定ですね。
\x82\xA0
みたいにHEXで記述して頂ければ大丈夫だと思います。

>IISではカスタムヘッダをログに記録出来ない
あら、そうなんですかぁ…
となると、IPアドレスの記録は本当に厳しい感じになっちゃいますね。

>どうやって起動するのがいいんだろう?
Windowsをサーバーとして使ったことがないので、全くわかりませんです。すみません。
「サービス」とかの概念も理解してないし(笑。
メーリングリストでネタ振りして頂けるといいかもしれません。

>アーカイブはWEBで公開されてませんか?
現時点では公開してませんが、ezmlmのコマンドで過去のメールをgetできるかと思います。
その場合には、とりあえず空メールをguardian-users-jp-help@jumperz.netに送ってみて下さい。
アーカイブの公開を考えているのですが、具体的にどうすれば良いのか分からず困っています。
mbox形式のアーカイブをHTML化するソフトウェアは見つけたのですが、僕のところはqmailを使っていてmbox形式じゃない(Maildir形式?)なんです。

けん :

Guardian側で%addrをUser-Agent等のログに記録できるヤツの最後に付け加えるとかができるとIISの救われるかな?(^^;

ike :

金床さん。
>無事に起動・動作したようでほっとしてます(笑。
操作、設定などが分かりやすく、よい感じでしたー :) 。
(まだ見てない設定ファイル、機能もありますが)

結構、正しいか怪しい事も書いてるんで、間違ったらどんどん指摘してください。

「MShutdownClient」クラスを叩いてシャットダウンする時に「java.net.SocketException」を吐くのは正規の動作なのかなぁとか不安になってます。

プラグインなど触ってない機能もあって、ちょっとアップアップです。(^^;

「あ」とマッチングを取りたい場合、「pattern」に「\x82\xA0」と書く方法ではダメかもしれません。「%82%A0」だと平気そうですねー。

本文に少し追記しましたが、「マルチバイト文字とのマッチング」(=「decodedRequestBody」にした時の動作 の項目)ってややこしいですね。

メーリングリストですが、ヘルプの取り寄せ出来ました。ありがとうございます。
ヘルプにかかれている過去メールの取り寄せ方法(取り寄せアドレス)は英語版と同じになってますね?
最初取り寄せたら、英語版が送られてきてびびりました(^^;)
# 誰でも取得できるって事かしら?
「-jp」つけて送り直したらちゃんと取得できました。

チラッと見ましたが、今日は疲れてしまったので、読むのは後日にします〜。
サポートの場があるのに、ここで質問するのもおかしな話ですし、近々、お邪魔したいと思ってます〜。

今後ともよろしくお願いしますー。

ike :

けんさん。

あぁ、なるほどー。
ログの特定のフィールド(例えばリファラ)にIPアドレスを追加して、2フィールド分の内容を書いちゃうんですね。

個人的なことを言うと、私はLogPerserでログをいじってるので、LogPerserに対応してると嬉しいです。(欲張り)

LogPerserはヘッダ行も読んでるみたいなのすよねぇ。
例えば、リファラのデータの前に %{X-Client-Addr}i を追加していただければ (他力本願) 、元のIPアドレス用のヘッダ( = c-ip )を適当な文字列に置換して、リファラ( = cs(Referer) )を、「c-ip cs(Referer)」とか置換すればLogPerserから扱えるフォーマットになるかもと思いました(未確認)。順番も見てるのかなぁ?

あ、「Guardian@JUMPERZ.NET」で、IISのフォーマットでも、commonフォーマットでも、combineフォーマットでもアクセスログをはいていただければ、、、?(他力本願)

オープンソースなんだから、自分でやれといわれそうだけど、スキル的に厳しそう〜。

# 前から気になっていたんですが、けんさんは、ぼやいたり、ほかほかだったりするけんさんですか?

金床 :

>「MShutdownClient」クラスを叩いてシャットダウンする時に「java.net.SocketException」を吐くのは正規の動作なのかなぁ
正しいです(汗
ここで例外吐いちゃうのは確かに美しくないのですが…
余裕があればそのうち修正したいと思います。

>「あ」とマッチングを取りたい場合、「pattern」に「\x82\xA0」と書く方法ではダメかもしれません
今手元でテストしてみましたが、いけましたよ。「あ」がShift_JISじゃないとダメです。

>最後の「1」が1回目のマッチングでマッチします。
>予期しない動作かも?

pattern=1
ということは、つまりリクエストボディ中に「1」という文字列が存在するかどうかチェックしたい、ということになりますよね。
さらに
type=decodedRequestBody
にしているということは、「1」がURLエンコードされていても発見したいということです。

リクエストボディが%82%B1であれば当然「1」を含むわけですから、これでマッチするのは正しい動作となります。

金床 :

はっ…
「あ」とマッチング取りたい場合って
ブラウザのテキスト入力欄などに「あ」って入れるって意味ですね、なるほど。
#直接HTTPリクエスト中に「あ」を入れるということかと誤解してました

その場合はご指摘通りURLエンコードした文字列をpatternとして使って頂き、type=requestBodyでいけると思います。

ike :

金床さん。
すいません。
暫く、家でパソコン全然見てませんでした・・・。

>ここで例外吐いちゃうのは確かに美しくないのですが…
了解です。
シャットダウンの処理の途中で落ちてるのかなぁって思っただけですー。
そうじゃなければ、大丈夫ですー。

>その場合はご指摘通りURLエンコードした文字列をpatternとして使って頂き、type=requestBodyでいけると思います。
了解しましたー。

MLに投稿するぞ投稿するぞと、時間が過ぎてますー。
近いうちに・・・。

コメントする


画像の中に見える文字を入力してください。

このブログ記事について

このページは、ikeが2004年10月20日 18:27に書いたブログ記事です。

ひとつ前のブログ記事は「古いエントリの変更履歴 (2004/10)」です。

次のブログ記事は「fireFTP」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

最近のコメント

On Guardian@JUMPERZ.NET
  • ike: 金床さん。 すいません。 暫く、家でパソ
  • 金床: はっ… 「あ」とマッチング取りたい場合っ
  • 金床: >「MShutdownClient」クラ
  • ike: けんさん。 あぁ、なるほどー。 ログの
  • ike: 金床さん。 >無事に起動・動作したようで
  • けん: Guardian側で%addrをUser
  • 金床: 試して頂きまして大変ありがとうございます
Powered by Movable Type 4.261