バッドリクエストをよこすIPアドレスをAWS WAFを使ってブロックするには
インターネット向けのWebアプリケーションは非常に頻繁にスキャンあるいはプローブされます。それはときには良い目的で、ときには弱点を特定するために行われます。とりわけそれらを特定するためのツールを持ってないのであれば、そのように悪用される可能性がある試みの意図を調べるために、幾つかの調査を行うことになります。それらを識別し、不要なトラフィックをブロックする方法の一つが、AWS WAF を使うことです。 AWS WAFはweb application firewallのひとつで、セキュリティを侵害したり、アプリケーションに不要な負荷をかけるような悪い試みからWebアプリケーションを保護するのに役立ちます。
一般的には、それらの行動は自動化されています。攻撃者の意図はあなたのWebアプリケーションの使っているソフトウェアバージョンやインターネット向けに晒されているURL等の情報を収集することです。Webアプリケーションが脆弱であるかもしれない場所についてのデータを収集する「偵察任務」と考えるとわかりやすいでしょう。脆弱であるかを調べるために、彼らは一連の要求を送信し、その応答を取得します。その過程では、HTTP 4xx エラーが多くの場合発生します。通常の要求でもこれらのエラーコードは発生することはありますが、単一のIPアドレスからのエラーが多ければ、悪意をもってWebアプリケーションを利用している兆候の可能性があります。
Amazon CloudFrontをつかってWebアプリケーションを動作させているのであれば、それらのログはCloudFront access logsで見つけることができます。それらのエラーコードを元に、AWS WAFの設定をアップデートして、エラーコードの発生源からのアクセスをブロックするような、 AWS Lambda のコードをつくることにしましょう。
S3上に送られたCloudFrontのアクセスログを自動的にパースして、特定のアクセス元(IPアドレス)からのbad requestを数えて、そのアドレスからのそれ以降のアクセスをブロックするようなLambda functionの作り方をご案内します。また、あわせて、ご自身で試せるように、Web ACL (Access Control List)、ルール、Lambda function、S3上のログバケットを作成するCloudFormation templateを提供します。
ソリューションの概要
How to Configure Rate-Based Blacklisting with AWS WAF and AWS Lambdaという私の同僚であるHeitor Vitalによる最近のブログ記事(英語)を元に拡張します。 コンセプトはそのままで、トータルのリクエスト数のかわりに、IPアドレス別のHTTP 4xxエラーコードを使います。このソリューションは、 あなたが CloudFront distributionを持ち、 CloudFormationに慣れていることを前提とします。
このソリューションの流れは、
- CloudFrontはdistributionのアクセスログファイルを一時間に数回にわけて設定されたS3バケットに置きます。このバケットは、Lambda functionおよびCloudFormationスタックと同じリージョンにあるものとします。
- 新しいログファイルがS3に届くと、Lambda functionが呼び出されます。ログファイルは解析され、400, 403, 404, 405毎にカウントされて、一時的に結果はS3バケット内のcurrent_outstanding_requesters.jsonファイルに保存されます。
- ユーザが定義した閾値以上となったIPアドレスからの要求は、AWS WAFによってブロックするようにアップデートされます。
- Lambda functionはCloudWatchのカスタムメトリクスに、ブロックしているIPアドレス数と、アクセス数を送ります。
Lambda function の概要
構成は以下のとおりです
- 関連するPython modulesをインポートします。
- 次に、エラーコードを検索(29行目)し、S3に出力するファイル名をOUTPUT_FILE_NAMEで指定しています。LINE_FORMATパラメータはログのフォーマットを決定します。設定はCloudFrontのためのものになっていますので必要に応じて変えることができます。
- 関数毎の担当概要は次の通りです。
- def get_outstanding_requesters – ログファイルの解析.
- def merge_current_blocked_requesters – ブロックの有効期限制御.
- def write_output – 現在のIPアドレスのブロック状態を current_outstanding_requesters.jsonに書き込み
- def waf_get_ip_set – 現在のAWS WAFサービスのIPSetの取得.
- def get_ip_set_already_blocked – IPSetがすでにブロックされているかの判定.
- def update_waf_ip_set – AWS WAF IPSetのアップデート.
- def lambda_handler – CloudFormationで定義した値の読み込みとCloudWatchメトリクスの更新.
AWS Management Consoleをつかってデプロイ
CloudFormationコンソールを使います:
- Lambdaが使えるリージョンを使うことを忘れないで下さい。 Region Table にリージョン毎の対応サービス一覧があります。
- Create Stackを押してtemplate URLに https://s3.amazonaws.com/awswaf.us-east-1/block-bad-behaving-ips/block-bad-behaving-ips_template.json を入れて下さい。そしてNextをクリック
- スクリーンショットを参考に、パラメータを入力します。
- S3 Location – CloudFrontのログファイルが置かれるS3バケット
- Request Threshold – 単一のソースアドレスからの4xxを許容する1分あたりの数。デフォルトは 50。
- Optional: 必要であればタグを指定. Nextをクリック
- チェックボックスで、コストがかかることを認識したことを示して、Createをクリック。.
- コストの詳細については、 AWS WAF pricing information, Lambda pricing information, および CloudFront pricing informationを御覧ください
Testing
スタックが作成された後、 このテストファイルを作成したS3 bucket にコピーするとLambda functionをテストすることができます。また、既にお持ちのCloudFrontログファイルをコピーしてテストすることもできます。Lambdaのコンソールで、 Monitoring をクリックすればCloudWatch Logsでログを確認できます。S3バケットには 今現在ブロックされているIPアドレスの詳細が書かれたcurrent_outstanding_requesters.jsonファイルが含まれていることが確認できます。
正常に動作していることを確認したら、CloudFrontのディストリビューション設定を変更し、作成したバケットにログファイルを送るように設定します。Lambdaのコンソールから、動作していることが確認できます。さらに、現在のIPブロックを確認するためにAWS WAFコンソールも使えます。ACLにはMalicious Requestersがあり、 Auto Block Rule Setという名前のIPの一致条件にリンクされている自動ブロックのルールが表示されます。また、手動でブロックするIPアドレスを追加するための、マニュアルのブロックルールも表示されています。
最後に、ブロッキングを実施するために、CloudFrontディストリビューションと、WebACLを関連づけます。
4xxのエラーは通常のリクエストに対しても返されることがあることは覚えておいてください。ページや画像の欠落がないように閾値の設定をしてください。閾値をどうするべきかわからないのであれば、ルールのActionをBlockの代わりにCountにします。自信がついてきたら、Blockに変更します。
まとめ
この記事で、エラーカウントにもとづいて、自動的にIPアドレスをブロックするように設定する方法を紹介しました。アイディアや疑問があれば、AWS WAF forumでコメントください。
- Ben 本記事のオリジナル版はこちら。日本語版は荒木が担当しました。
コメント