2012年3月11日日曜日

はてなブックマークボタンを外しました

この数日間問題になっている「はてなブックマークボタン」ですが、当日記およびHASHコンサルティングオフィシャルブログにも、当該ボタンがついていました。何が問題であるかは以下が詳しいですが、要は、はてなの管理下でない当サイトで、はてなのブログパーツが読者の皆様のトラッキングをしていることが問題です。

参考:
私は、2006年11月に、はてなダイアリーで日記を書き始めて以来、一貫してはてなのサービスを利用してきましたので、当ブログにも「はてなのボタンもつけとかなきゃな」程度のノリでボタンをつけておりました。その時点では、上記問題は知られておらず、また公式には始まってもいなかったようですので、知りようのないことではありましたが、それでも私の責任はあると認識しております。

私の本のP62には以下の記述があります。

第三者のJavaScriptを許可する場合
XSSは悪意の第三者によるJavaScript実行が問題でしたが、意図的に第三者のJavaScriptを実行させる場合があります。セキュリティ上の問題に対しては、サーバー運営者あるいは閲覧者が第三者を信頼する形で実行されます。

◆ サイト運営者が第三者を信頼して実行するJavaScript

サイト運営者が第三者の提供するJavaScriptを自サイトに埋め込む場合があります。典型的には、アクセス解析、バナー広告、ブログパーツなどです。このケースでは、サイト運営者が意図的にJavaScriptの提供元である第三者(以下提供元と表記)のJavaScriptを埋め込みます。
このように埋め込まれたJavaScriptに悪意があると、情報漏洩やサイト改ざんの危険性があります。このため、提供元が信頼できることが条件になりますが、実際には以下のような脅威があり、セキュリティ上の問題が何度も発生しています。
  • 提供元が意図的に個人情報を収集す
  • 提供元サーバーに脆弱性があり、JavaScriptが差し替えられる
  • 提供元のJavaScriptに脆弱性があり、別のスクリプトが実行させられる
バナー広告などのJavaScriptとXSSの結果動作するJavaScriptには、技術的に見れば同一の脅威があります。両者の違いはサイト運営者が提供元を信頼して意図的に埋め込んでいるかどうかです。従って、意図的に埋め込むJavaScriptについても、提供元の信頼性を十分調査した上で、保守的で慎重な判断が求められます

例示の箇条書きのところで「(JavaScriptの)提供元が意図的に個人情報を収集する」という箇所があてはまります。引用部の最後の箇所「意図的に埋め込むJavaScriptについても、提供元の信頼性を十分調査した上で、保守的で慎重な判断が求められ」るにも関わらず、私自身が実行できておりませんでした。

という状況でしたので、当該のブックマークボタンは昨日撤去致しましたことを報告します。
また、はてなの日記の方でも、一時ついカッとなって類似のボタンを撤去しましたが、今は戻しています。その理由は以下の通りです。
  • はてなの管理下のサイトではこの問題はそもそも関係ない
  • はてなのサイトでは、 トラッキングはボタンとは別の方法で実装できるので ブックマークボタンだけを目の敵にしても意味がない

ですが、当面の間、はてなのサービス(ブックマーク、日記)は少なくとも新規の更新をやめようと思います。読者の皆様にはご不自由をお掛けしますが、代替として以下のサービスをご覧下さい。


以上、ご報告致します。

2012年2月20日月曜日

難読化していないAndroidアプリケーションは脆弱性か

このエントリでは、Androidアプリケーションにおいて、難読化が施されていない場合、脆弱性にあたるかについて議論します。

はじめに

Androidアプリケーションは主にJava言語で記述され、DEX形式のファイルにコンパイルされたコードを、DalvikというJava互換VM上で実行します。DEXおよびAPKファイルの仕様は公開されており、DEXにはクラスやメソッド等のシンボル名も含まれているため、リバースエンジニアリングが容易であると言われています。このため、Android SDKには標準でProGuardという難読化ツールが添付されています。
それでは、難読化の目的はそもそも何で、難読化でその目的は達成されるのでしょうか。

難読化の目的

Webアプリケーションの場合は、重要なロジックは主にサーバー側に存在するため、ソースコードを外部から取得することはできません。これに対して、スマートフォンアプリケーションの場合は、実行プログラムが手元の端末上にあるため、リバースエンジニアリングにより、(手間の大小はともかく)ソースコードを再現させることが可能です。
リバースエンジニアリングに対抗するために、プログラムを解析しにくくする行為を難読化と呼びます。
難読化の典型的な目的を以下に示します。

  • アプリケーションロジックの流出防止
  • 内部の隠れた脆弱性の発見防止
  • 課金コードの改変による不正利用の防止
  • アプリケーションの不正流用の防止
  • 暗号鍵など秘密情報の漏洩防止

ProGuardとは

ProGuardとは、Android SDKに標準で添付される難読化ツールです。ProGuardには複数の機能がありますか、難読化に寄与するものとしては、クラスやメソッドの名前の付け替え(連番のような形になる)があります。
クラス名やメソッド名から意味がわからなくなるため、リバースエンジニアリングがしにくくなることを期待しての機能でしょう。

ProGuardで十分なのか

セキュリティの専門家の立場から見ると、ProGuardの提供する機能は中途半端です。一般的に、リバースエンジニアリングというと、機械語のバイナリからの解析を指します。職業的にリバースエンジニアリングをしている人たち、例えばウイルス対策ソフトのマルウェア解析担当者は、なんのヒントもないマルウェアのバイナリを解析して、マルウェアの挙動を把握し、パターンファイルを作成しているわけです。最近のマルウェアは、単純な機械語ではなく、加えて難読化が施されていて解析が難しくなっていると言われています。
これに対して、ProGuardの「難読化」の結果は、機械語に比べるとはるかにリバースエンジニアリングが易しいと言えます。シンボルが除去されるとは言え、アプリケーションが利用するライブラリのシンボル名などは除去できないためです。
すなわち、ProGuardの効果は、「very easyをeasyにする」程度のものと言えます。このあたりの感覚については、杉山俊春氏の寄稿記事も参考になります。


商用難読化ツールはどうか

ProGuardはどうももの足りないということであれば、商用難読化ツールというものもあります。以下に、Android向けの商用難読化ツールを紹介します。
※いずれの製品も私自身は評価しておらず、推奨というわけではありません。

一例として、DashOの機能を見てみると、以下のような難読化機能が提供されています。
  • 改ざん検出と通知 
  • 名前の変更
  • 制御フローの難読化
  • 文字列の暗号化
  • バイトコードの最適化
  • ウォーターマーク(出所を追跡可能に)

このうち、名前の変更とバイトーコードの最適化はProGuardにもある機能ですが、これら以外はProGuardにはない機能です。
難読化というからには、この程度はやって欲しい気がしますが、商用難読化ツールは高価(DashOは最小構成で79万円)なため、手軽に導入するわけにはいきません。

ではどうするのがよいか

ProGuardでは頼りない、商用難読化ツールは高価だとすると、どうすればよいのでしょうか。
その答えは、先に紹介した杉山氏の記事タイトル『見せたくないなら「持たせない」が鉄則』だと思います。具体的には、見せたくないリソースやロジックは極力サーバー側に持たせ、スマートフォン側には、入力や表示など最低限の機能に絞ることです。
それでも、なんらかの事情により難読化したい場合はあるでしょうが、以下のように考えればよいでしょう。

  • リバースエンジニアリングによる想定被害金額を見積もる
  • 想定被害金額が商用難読化ツール購入費用よりも大幅に大きければ、商用難読化ツールにより難読化処理する
  • 想定被害金額が大きくなく、費用対効果が見合わない場合は、ProGuard+手動難読化を施す

手動難読化とは私の造語ですが、プログラムロジックを故意に複雑にすることで、リバースエンジニアリングの邪魔をすることです。冗長なコードを挿入したり、文字列をエンコードあるいは暗号化した状態で保持して、アプリケーション内でデコードあるいは復号するなどです(面倒です)。
手動難読化も、あまり期待しない方がよいとは思いますが、ソースコード診断をしていると「まるで難読化されたような」読むのが嫌になるソースコードに出くわすこともしばしばですので、プログラムの下手な人に依頼すると思わぬ効果があるかもしれません(冗談です)。

また、そもそも難読化はリバースエンジニアリングを難しくするものであり、不可能にするものではないので、リバースエンジニアリングによる影響は受容可能にしなければなりません。例えば、リバースエンジニアリングによって、大量の個人情報が漏洩するような設計はダメだと言うことです。


まとめ

以上をまとめると以下のようになります。
  • 難読化するか否かはアプリケーション要件である
  • 難読化が破られリバースエンジニアリングされた場合でも、影響が受容可能であるように設計する
  • 本当に難読化の必要な場合はProGuardでは機能不足であり商用難読化ツールを検討する必要がある
  • 商用難読化ツールは高価なので、導入にあたっては費用対効果の検討が不可欠

ということで、表題の「難読化していないAndroidアプリケーションは脆弱性か」という問の答えは、「一般には脆弱性とは言えず、アプリケーション要件である」が答えだと考えます。


[PR]
3月2日、株式会社DNPデジタルコム主催の「スマートフォン向けセキュリティセミナー」(五反田、無料)で基調講演します。この中で、スマートフォンアプリケーションのセキュリティに関する責任範囲や対策などについて、基礎的なところから説明できればと思います。

スマートフォンアプリケーションのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

2012年2月6日月曜日

スマートフォンアプリケーションでSSLを使わないのは脆弱性か

このエントリでは、スマートフォンアプリケーションの通信暗号化の必要性について議論します。

はじめに

先日、スマートフォンアプリケーションのセキュリティに関するセミナーを聴講しました(2月8日追記。講演者からの依頼によりセミナーのサイトへのリンクをもうけました)。この際に、スマートフォンアプリケーションの脅威に対する共通認識がまだないという課題を改めて感じました。その課題を痛感できたという点で、セミナーは私にとっては有益でした。
このため、当ブログではスマートフォンアプリケーションの話題をあまり取り上げていませんでしたが、今後は、とりあげようと思います。まずは、スマートフォンアプリケーションでは暗号化を必須とするべきかという話題です。この話題は、前記セミナーでもとりあげられていました。

暗号化の目的は何か

まず、暗号化の必要性を論じるためには、暗号化の目的を明確にする必要があります。前記セミナーでは、この目的が明確に示されていませんでした。
一般的に、通信を暗号化する目的には、以下の2つの可能性があります。
  • 第三者からのデータ盗聴を防ぐため
  • 第三者だけでなく、アプリ利用者にもデータ通信の内容を見せないため
第三者の盗聴を防ぐ目的にはSSLを使用すればすむことですが、SSLはデータの利用者に通信内容を見せない機能はありません。一般のWebアプリケーションの場合は、通信内容はすべて利用者には開示されるという前提でアプリケーションを開発するので、これでよいわけです。
先のセミナーでは、質疑応答にて、SSLだと利用者には通信内容が見えてしまうので、GET/POSTの内容を見せないような暗号化が望ましいと説明していました。つまり、SSLではなく独自の暗号化ということでしょうが、そうすべき理由は明確に説明されませんでした。

利用者にも通信内容を見せない理由

利用者にも通信内容を見せたくない動機は、悪意の利用者を想定してのことです。この想定自体は妥当です。
では、悪意の利用者のどの行為を防ぎたいのでしょうか。以下の二種類が考えられます。
  • サーバーの脆弱性をついた攻撃
  • ゲームなどで、正規のアプリでは困難なプレイを実現する不正なクライアントの作成
先の講演では、なんとなく前者を目的とした暗号化のように私には聞こえましたが、もしそうであれば、危険な発想です。

「隠すこと」による脆弱性対策は危険

通信内容を隠してしまえば攻撃もできなくなるだろうという発想は危険です。完全に隠し通せるならともかく、完全な隠蔽は困難であるからです。
その理由は、スマートフォンアプリケーションの場合、暗号鍵を隠すことが困難であるからです。アプリケーションのリバースエンジニアリングが可能なので、鍵の保存方式を解析されれば、暗号を破ることができます。このため、アプリの難読化ということをするわけですが、あくまで「難読」であって、「不可読」ではないので、鍵を盗まれる可能性はあります。
このため、サーバー側の脆弱性対策については、Webアプリケーションと同様に「全ての通信内容は把握される」ことを前提として、脆弱性を元から断つことが必須です。

独自の暗号化が必要な場合

一方、ゲームなどのアプリケーションの場合、不正プレイを防止する等の目的で、通信内容を秘匿したいニーズがあります。
この場合も、前述のように、通信方式がばれるリスクはあるわけですが、以下のように考えるとよいでしょう。
  • 通信方式が解読された場合でも、利用者の個人情報などは漏洩しないよう実装する
  • 通信方式が解読された場合に備えて、サーバー側ロジックにも不正プレイ対策を組み込む
  • その上で、独自の暗号化とアプリの難読化を施す
このように、通信方式が解読されても利用者の不利益にならないようにする一方、サイト運営者の不利益が受容可能なレベルになるようにサーバー側で対策します。

独自暗号化のデメリット

一方、独自暗号化にはデメリットはないでしょうか。私は、独自暗号化にはデメリットもあると考えます。
最近のスマートフォンアプリをめぐる話題として、プライバシー情報の不正送信というテーマがあります。このため、アプリ提供者には以下が求められるわけです。
  • アプリの実現に必要最低限のパーミッションを用いる
  • 取得およびサーバー送信するプライバシー情報を開示する
しかし、プライバシー情報を取得できるパーミッションを得ているアプリの場合、送信していないと表明しても、「本当はサーバーにプライバシー情報を送信しているのではないか」という疑念は残ります。
このため、通信内容を監査可能な状態に保つ(SSLのみで暗号化する)ということは、アプリ提供者が身を守る上でも有効だと考えます。上記二項は守った上で、「調べたければいつでもどうぞ」という状態にしておけば、提供側も堂々と構えておけばよいわけです。
一方、利用者当人にも読めない暗号化がしてあると、「本当はプライバシー情報も送信しているのではないか」という疑惑は(パーミッションを外す以外の方法では)ぬぐえません。


スマートフォンアプリにSSL暗号化が要求される本当の理由

先のセミナーでは、スマートフォンアプリが通信を暗号化すべき理由として、従来型携帯電話(フィーチャーフォン、俗に言うガラケー)と比べてWi-Fiでの利用があり得るので、盗聴のリスクが増すからだと説明されていました。この説明自体間違ってはいませんが、もう少し深い理由があると私は考えます。
Webアプリケーションの世界では、SSL暗号化は「望ましい」条件であって必須とまではされていません。その理由は、SSLの使用に費用が掛かるためということもありますが、SSLを使っているかどうかは、ブラウザの錠前マークを見れば一目瞭然であるので、利用者が回線品質に不安があれば、SSL不使用の場合に自分の判断で利用を止めることができるからです。
一方、スマートフォンアプリケーションの場合は、アプリケーションがHTTP平文通信しているのか、HTTPSの暗号化通信を利用しているのかは、一般利用者には分かりません。
このため、今後スマートフォンアプリケーションでは、以下のように考えるとよいと思います。

  • アプリケーションの場合SSL通信しているかどうか利用者には分からないため、通信路をSSL暗号化していない場合にはその旨を告知することが望ましい
  • 告知せず平文通信している場合は、アプリケーションの脆弱性とみなすことを提案します(公開情報のみを通信している場合を除く)
  • 前提として、公衆無線LANには信頼性の低いものがあり、スマートフォンから利用されてしまうリスクが現実的に存在するため

追記(2012/2/8)

twitterで @bulkneets さんからコメントを頂きました。
徳丸さんの、平文で通信するiOSアプリの通信内容が改竄された結果として受信したレスポンスそのまま表示なりして、そのインジェクションされたコードから触れるAPIなりファイルなりが機密データだったら、そのアプリが扱ってる情報と関係なく危険なので公開情報のみ通信してるかどうかは関係ない(リンク)
確かにその通りです。
改ざんされた場合、コードが実行できない場合でも、間違った情報が見えるという時点でセキュリティ上の問題が生じる可能性はありますね。
ということで、「公開情報のみを通信している場合を除く」という但し書きは、大ざっぱな免責条項として書いたものですが、正確ではありません。安全サイドに倒すならば、「平文通信の場合は常に告知せよ、そうでなければ脆弱性」というガイドラインがよいことになります。

まとめ

スマートフォンアプリケーションのセキュリティ全般の話題の後、スマートフォンアプリケーションでは暗号化に対する要求がWebアプリケーションよりも厳しくなる理由を説明しました。
手元のTwitterアプリケーションなどを調べると、平文送信しているものもけっこう見かけます。それらが即脆弱だというほどの共通認識はできていませんが、今後の議論により、アプリの平文通信が脆弱性か否かや、脆弱性と言えるための条件等について、共通認識が得られればと希望します。


追記(2012/2/6 11:24)

言葉足らずの内容があり誤解を招いているようでしたので追記します。
SSLは監査可能というのは、診断用にCA証明書を追加した端末を使用するもので、端末のroot化が必要です。まともな診断業者ならやっていると思います。色々な方法がありますが、準備はかなり大変です。
誰でも監査可能という意味ではありません。


[PR]
3月2日、株式会社DNPデジタルコム主催の「スマートフォン向けセキュリティセミナー」(五反田、無料)で基調講演します。この中で、スマートフォンアプリケーションのセキュリティに関する責任範囲や対策などについて、基礎的なところから説明できればと思います。


スマートフォンアプリケーションのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。


2012年1月23日月曜日

ModSecurityをソースからビルドしてhashdos対策に活用する

このエントリではModSecurityをソースからビルドする方法を説明した後、hashdos専用のチューニングを施す流れを説明します。

はじめに

既にModSecurityについては、CentOS+yumおよびUbuntu+apt-getにより導入する方法を説明しています。このエントリでは、ModSecurityをソースからビルドする方法を説明します。
ModSecurityのビルドは依存関係が複雑であり、バージョンによってビルド方法が変わるなど、面倒な面があります。このエントリでは、CentOSとUbuntuの場合について、実際的なビルド方法を説明します。

準備するもの

ModSecurityは以下のプロダクトに依存しています(ModSecurity HandbookP27)。ビルドに先立って準備しておく必要があります。
  • Apache Portable Runtime(APR)
  • APR-UTIL
  • mod_unique_id
  • libcurl
  • libxml2
  • Lua5.1 (オプション)
  • PCRE

PCRE、libcurl、libxml2、Lua5.1の準備

これらはパッケージを用いて導入するとよいでしょう。

(1)CentOSの場合
Lua5.1以外は、yumで導入できます。
$ sudo yum -y install pcre-devel libxml2-devel curl-devel
CentOS6の場合、Luaもyumで導入できます。
$ sudo yum install lua-devel
CentOS5の場合、標準パッケージにLuaが用意されていません。Luaは必須ではないし、まだLuaを活用した事例はほとんどないので、通常はLuaなしでよいでしょう。
Luaを使いたい場合は、EPELリポジトリを使えばLuaを導入できます。hashdos攻撃をmod_securityで防御する(CentOS+yum編)を参照して、EPELパッケージを設定した後、以下でLuaを導入して下さい。
$ sudo yum --enablerepo=epel install lua-devel

(2)Ubuntuの場合
Luaも含めて、apt-getで導入できます。
$ sudo apt-get install libpcre3-dev libxml2-dev libcurl3-dev liblua5.1-dev

Apacheの再構築

次に、Apacheの再構築です。Apacheを再構築する理由は、ApacheにバンドルされるPCREが古く、ModSecurityの前提とするPCREのバージョンが異なるからです。このため、Apacheからも外部のPCREを呼び出すようにします(ModSecurity HandbookP30)。また、mod_unique_idが必要になるため、必要に応じてコンパイルします。
パッケージからApacheを導入している場合は、APRとAPR-UTILが入っていないので、開発版のApacheを導入します。

(1)ソースからApacheをビルドしている場合
デフォルトでAPR、ARP-UTILは元々入っています。mod_uniquie_idはコンパイルオプションのチェックをしてください。PCREも先のステップで導入ししたものをApacheからも利用します。
最小限のconfigureのオプションは下記となります。
$ ./configure --with-pcre --enable-so --enable-mods-shared="unique_id"

(2)CentOS+yumでAapcheを導入している場合
開発版のApacheを追加導入します。
$ sudo yum install httpd-devel

(3)Ubuntu+apt-getでApacheを導入している場合
開発版のApacheを追加導入します。
$ sudo apt-get install apache2-dev

mod_securityのビルド

次に、mod_securityのビルドです。configureの際に、以下のように前提モジュールのパスを明示してやるとトラブルの可能性が少ないようです。パスは適宜調整してください。
以下の例では、/usr/local/apache2にApacheが導入されていて、そこにModSecurityも導入する前提で説明しています。
$ cd
$ wget http://www.modsecurity.org/download/modsecurity-apache_2.6.3.tar.gz
$ tar xf modsecurity-apache_2.6.3.tar.gz
$ cd modsecurity-apache_2.6.3
$ ./configure \
  --prefix=/usr/local/apache2 \
  --with-apxs=/usr/local/apache2/bin/apxs \
  --with-apr=/usr/local/apache2/bin/apr-1-config \
  --with-apu=/usr/local/apache2/bin/apu-1-config \
  --with-pcre=/usr/bin/pcre-config \
  --with-libxml=/usr/bin/xml2-config \
  LDFLAGS=-L/usr/local/apache2/lib
$ make
$ sudo make install
ブログなどでは、--enable-performance-measurementを指定している例も見かけますが、これを指定するとModSecurityが遅くなり、ModSecurity自身がhashdos攻撃を受けるような挙動になります。このオプションは指定しないで下さい。

(2)ディレクトリの作成
次に、ModSecurityの使用するワーク用のディレクトリを作成します(ModSecurity HandbookP34~)。apacheの実行ユーザをapacheと仮定しています。適宜変更してください。
$ sudo mkdir /var/modsecurity/
$ sudo mkdir /var/modsecurity/data
$ sudo mkdir /var/modsecurity/tmp
$ sudo mkdir /var/modsecurity/upload
$ sudo chown root:apache /var/modsecurity
$ sudo chown apache:root /var/modsecurity/data
$ sudo chown apache:apache /var/modsecurity/tmp
$ sudo chown apache:root /var/modsecurity/upload/
$ sudo chmod 750 /var/modsecurity
$ sudo chmod 700 /var/modsecurity/data
$ sudo chmod 750 /var/modsecurity/tmp
$ sudo chmod 700 /var/modsecurity/upload

CRS(Core Rule Set)の導入

ModSecurity用の標準ルールセットとしてCore Rule Set(CRS)を導入します。

(1)ダウンロード、展開
http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/ から最新版をダウンロードします
$ cd
$ wget http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/modsecurity-crs_2.2.3.tar.gz/download
$ mv download modsecurity-crs_2.2.3.tar.gz  # downloadというファイル名になったのでリネーム
$ tar xvf modsecurity-crs_2.2.3.tar.gz

(2)CRSのコピー
CRSを定位置にコピーします。ここでは、Apacheホームディレクトリ下のcrsというディレクトリにコピーしています。
$ cd /usr/local/apache2/
$ sudo mkdir crs
$ sudo cp -r ~/modsecurity-crs_2.2.3/* crs

mod_securityの設定

modsecurity_crs_10_config.confという設定ファイルを作成します。exampleを元に修正します。
$ cd /usr/local/apache2/crs
$ sudo cp modsecurity_crs_10_config.conf.example modsecurity_crs_10_config.conf
$ sudo vi modsecurity_crs_10_config.conf
「#SecRuleEngine DetectionOnly」 という行を探し、その後ろに以下を追加します。
SecRuleEngine On
# SecRequestBodyAccess リクエストボディのチェックを有効にする(必須)
SecRequestBodyAccess On
SecResponseBodyAccess Off
# SecRequestBodyLimit はPOSTサイズの上限。できるだけ小さく設定する
SecRequestBodyLimit 5242880
# SecRequestBodyNoFilesLimit はファイルアップロード以外のPOSTサイズの上限。できるだけ小さく設定する
SecRequestBodyNoFilesLimit 51200
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
SecAuditLogType Serial
SecAuditLog logs/modsec_audit.log
SecAuditLogParts "ABIFHKZ"
SecDebugLog             logs/modsec_debug.log
SecDebugLogLevel        3
SecDataDir      /var/modsecurity/data/
SecTmpDir       /var/modsecurity/tmp/
SecUploadDir    /var/modsecurity/upload/

Apacheの設定

ModSecurity用のconfファイルを作成します。
$ sudo vi /usr/local/apache2/conf/extra/httpd-modsecurity.conf
以下の内容を入力します。
LoadModule unique_id_module modules/mod_unique_id.so
LoadModule security2_module modules/mod_security2.so

Include crs/modsecurity_crs_10_config.conf
Include crs/base_rules/*.conf
httpd.confを編集します。
$ sudo vi /usr/local/apache2/conf/httpd.conf
最後の行に以下を追加します。
Include conf/extra/httpd-modsecurity.conf
Apacheを起動します。
$ sudo apachectl start
エラーログに以下が出力されていることを確認します。
[Sun Jan 22 23:21:56 2012] [notice] ModSecurity for Apache/2.6.3 (http://www.modsecurity.org/) configured.
[Sun Jan 22 23:21:56 2012] [notice] ModSecurity: APR compiled version="1.4.5"; loaded version="1.4.5"
[Sun Jan 22 23:21:56 2012] [notice] ModSecurity: PCRE compiled version="7.8"; loaded version="7.8 2008-09-05"
[Sun Jan 22 23:21:56 2012] [notice] ModSecurity: LUA compiled version="Lua 5.1"
[Sun Jan 22 23:21:56 2012] [notice] ModSecurity: LIBXML compiled version="2.7.6"
ModSecurityが起動して、APR、PCRE、LUA、LIBXMLがロードされていることを確認してください。LUAはオプションですので、設定していない場合はロードされていなくても構いません。
次に、正常系のアクセスを確認します。以下のURLはサンプルですので、既存コンテンツのURLを指定して下さい。
http://example.jp/index.php
次に、以下がmod_securityによりブロックされることを確認します。既存コンテンツの後ろに、「?union+select」をつけてアクセスします。
http://example.jp/index.php?union+select
403 Forbiddenのエラーが表示されれば、mod_securityが稼働していることになります。

hashdos向けのチューニング

次に、hashdos向けのカスタマイズです。modsecurity_crs_23_request_limits.confに、Cookie数の制限のルールを追加します(Cookieによるhashdos攻撃と対策参照)。
$ sudo vi /usr/local/apache2/crs/base_rules/modsecurity_crs_23_request_limits.conf
以下のルールを探します。
# Maximum number of arguments in request limited
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,block,msg:'Too many arguments in request',id:'960335',severity:'4',rev:'2.2.3'"
        SecRule &ARGS "@gt %{tx.max_num_args}" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
このルールの次に、以下を追加します。Cookieの最大数が30にハードコードされているので適宜変更してください。
SecRule &REQUEST_COOKIES "@gt 30" "phase:2,t:none,deny,log,auditlog,ctl:auditLogParts=AFHZ,status:413,msg:'Too many cookies in request',id:'960336',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
次に、base_rulesから必要なルールのみを選択するために、activated_rulesというディレクトリに必要なルールのシンボリックリンクを作成します。以下のステップは、CRSを(SQLインジェクション対策など)フルに活用する場合は省略して下さい。
$ cd /usr/local/apache2/crs/activated_rules
$ sudo ln -s ../base_rules/modsecurity_crs_23_request_limits.conf .
$ sudo ln -s ../base_rules/modsecurity_crs_49_inbound_blocking.conf  .
$ sudo ln -s ../base_rules/modsecurity_crs_60_correlation.conf .
httpd-modsecurity.confを修正します。
$ sudo vi /usr/local/apache2/conf/extra/httpd-modsecurity.conf
最終行を以下のように変更します。
##Include crs/base_rules/*.conf
Include crs/activated_rules/*.conf
Apacheを再起動します。
$ sudo apachectl graceful
以上で、ModSecurityがhashdos専用にチューニングされました。

まとめ

ModSecurityをソースからビルドして、hashdos対策専用のチューニングを施す流れを説明しました。
ModSecurityは導入や設定がやっかいで、バージョンアップの際に互換性が損なわれる場合が多いので、大々的には推奨しにくい状況ですが、Apache Killerhashdosのように、あたらな脅威が発覚した際の緊急対処用のツールとしては有効だと思いました。フルのCRSは過剰検知が多くて使いにくい(チューニングが必須)と思いますが、上記のように特定の脅威向けに絞って活用することは有効だと思います。

追記

Apacheの設定の記述漏れがありましたので追記しました。


[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

2012年1月19日木曜日

Cookieによるhashdos攻撃と対策

このエントリでは、Cookieを用いたhashdos攻撃の可能性について検討し、実証結果と対策について報告します。

はじめに

既に当ブログで報告の通り、hashdosと呼ばれる攻撃手法が公表されています。HTTPリクエストのパラメータ名に対するハッシュ値を故意に同一にした(衝突させた)ものを多数(数万程度)送信することにより、Webサーバーを数分程度過負荷にできるというDoS攻撃手法です。
先の記事でも説明しているようにPOSTパラメータ(HTTPリクエストボディ)に多数のパラメータを仕込む攻撃が典型的ですが、POSTパラメータ以外のパラメータを用いた攻撃についても検討しておかないと、防御漏れの可能性が生じます。
そこで、POSTパラメータ以外を用いた攻撃方法について検討します。

POST以外に多数のパラメータを仕込めるか

POST以外に多数のパラメータを仕込む場所があるでしょうか。候補となるのは、以下と考えられます。括弧内は、PHPの該当変数です。
  • URLのクエリ文字列($_GET)
  • HTTPリクエストヘッダ($_SERVER)
  • Cookie($_COOKIE)
クエリ文字列($_GET)については、URLの長さの条件、あるいはHTTPリクエストラインの制限に引っかかります。Apacheの場合リクエストラインの制限はLimitRequestLine ディレクティブにより定義され、デフォルト値は8190バイトです。PHPに対するhashdosのPoCのサイズは約1.4メガバイトですから、8190バイトの制約では攻撃には至らないと考えられます。hashdosによる演算時間は、ハッシュ値の一致するパラメータ数の自乗に比例するためです。
リクエストヘッダ($_SERVER)の最大数は、Apacheの場合、LimitRequestFields ディレクティブで定義され、デフォルト値は100です。前述のPoCのパラメータ数は65536ですから、100という制限ではまったく攻撃には至らないと考えられます。
ということで、攻撃の余地が残るパラメータはCookieに絞られました。

Cookieによるhashdosの可能性

多数のCookieを用いたhashdos攻撃の可能性はどうでしょうか? などと書くと、RFC上のCookie数の制限を思い浮かべる方がおられるかもしれませんが、hashdosは能動的攻撃ですので、WebサーバーがどれだけのCookieを受け入れる実装になっているかに依存します。ブラウザの制限やRFC上の制限は関係ありません。
通常、Cookieは単一のCookieヘッダにより送信するので、HTTPリクエストヘッダ一つあたりのバイト数に制約されます。Apacheの場合、LimitRequestFieldSize ディレクティブにより定義され、デフォルト値は8190です。クエリ文字列の場合と同じサイズですので、このままではhashdos攻撃はできません。
しかし、複数のCookieヘッダが使えるとしたら話は変わります。最大100のCookieヘッダが使えることになり、8190×100=約800Kバイトが攻撃に使えることになります。これは攻撃には十分なサイズです。

PHPは複数のCookieヘッダを受け入れる

PHPが複数のCookieヘッダをどのように処理するかを以下のPHPスクリプトcookie.phpにより検証します。このスクリプトにはXSS脆弱性があるので、検証環境で試してください。
<?php
  var_dump($_COOKIE);
?>
以下のリクエストに対して
GET /cookie.php HTTP/1.0
Cookie: a=1;
Cookie: b=2;
以下のレスポンスが返ります。
array(2) {
  ["a"]=>
  string(1) "1"
  [",_b"]=>
  string(1) "2"
}
Cookie bも受け入れられてはいますが、改行のところでbの前にゴミの文字列が入っています。これは、hashdos攻撃に悪影響があります。
以下のリクエストではどうでしょうか。セミコロンを先頭に持ってきています。
GET /cookie.php HTTP/1.0
Cookie:;a=1
Cookie:;b=2
以下のレスポンスが返ります。
array(2) {
  ["a"]=>
  string(3) "1, "
  ["b"]=>
  string(1) "2"
}
こんどは、a, bともに名前の方にゴミはありませんが、aの値側にゴミが入りました。しかし、hashdos攻撃ではキー(パラメータ名)のみが問題になるので、攻撃には支障ありません。すなわち、PHPは複数のCookieヘッダを受け入れ、hashdos攻撃に悪用可能であると予想されます。
また、前述のPoCは、パラメータ名がパーセントエンコードされています。Cookieの場合、パーセントエンコードは必須ではありませんが、PHPの場合、名前・値とも受け取ったCookieをパーセントデコードします。すなわち、既存のPoCがCookieにも流用できることになります。

Cookieを用いたhahsdos攻撃ようのリクエストを作成する

ここまで検討したので、Cookieを用いたhashdos攻撃が成立するか、実際に試してみましょう。
POSTパラメータ用のPoCデータは、a=&b=&c=...という形式になっています。これを;a=;b=;c=...という形に変形した上で、8190バイトの制限内で、複数のCookieヘッダに切り分ける必要があります。
この処理をPerlスクリプトとして作成しました。以下に主要部分を示します。変数$aにPOSTパラメータ用のPoCデータが入っている想定です。
1: $a =~ s/&/;/g;
2: for (my $i = 0; $i < 100 && length($a) > 0; $i++) {
3:   $a =~ s/^(.{1,8180}\;)//;
4:   print "Cookie:;$1\n";
5: }
1行目で、&をセミコロン「;」に全て変換します。その上で、先頭から8180文字以内のセミコロンで終わる部分文字列を探して切り出します(3行目)。切り出した文字列は、Cookieヘッダして出力しています(4行目)。Apacheのデフォルトの制限に従い、Cookieヘッダは100個以下となるように制限しています。

試してみる

このようにして作成したCookie用PoCをPHPスクリプトにリクエストしてhashdos攻撃をしてみました。リクエストの送信には、Burp Suiteに含まれるRepeaterというツールを用いました。
結果は以下の通りです。
  • Cookie数:38166個
  • 実行時間:約4分半
hashdos攻撃の最中はCPU使用率は99%以上となりました。DoS攻撃の成功です。

対策

hashdos攻撃に対する従来の対策のうち、リクエストボディのサイズやPOSTパラメータの個数を制限する回避策は、Cookieによるhashdos攻撃には効果がありません。一方、以下は効果があります。
  • hashdos対策版のパッチを適用する(PHPの場合は5.3.9にバージョンアップしてmax_input_varsを設定する。デフォルト=1000のままでもよいが、小さいほど影響を受けにくい)
  • リクエストの処理時間を制限する(PHPの場合はmax_input_timeを小さな値にする)
  • suhosinパッチによりCookieの個数を制限する(デフォルトの最大数は100)
また、WAFによりCookieの個数を制限できれば、攻撃を回避できます。先のエントリで紹介した方法では、Cookieの個数は制限されないため、以下のエントリに追記をしておきましたので参照ください。


まとめ

Cookieによるhashdos攻撃について検討しました。理論的にCookieによるhashdos攻撃が可能であることを示した後、PoCを作成して攻撃が成立することを確認しました。
POSTパラメータを用いた攻撃への対処が、Cookieによる攻撃にも有効とは限らないので注意が必要です。



[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。


2012年1月5日木曜日

hashdos攻撃をmod_securityで防御する(Ubuntu+apt-get編)

このエントリでは、hashdos対策としてのmod_securityの導入と設定の方法を説明します。Ubuntu環境でapt-getによりApacheを導入しているサイトに対して、apt-getによりmod_securityを導入するというシナリオで説明します。

はじめに

背景などについては昨日のブログを参照してください。
このエントリでは、hashdos対策を目的として、Ubuntu環境にapt-getによりmod_securityを導入する方法を説明しますが、mod_securityに対する情報があまりないため、いったんフルのmod_securityを導入した後、hashdos専用のカスタマイズを施すという流れで説明します。

Ubuntuにapt-getでmod_securityを導入する

ModSecurity Handbookによると、DebianおよびUbuntuに対して、mod_security用のパッケージが用意されている(同書P31)ということですので、試してみましょう。
# apt-get install libapache-mod-security
これでmod_securityのインストールは終わりです。簡単ですね。

mod_securityの設定

CentOSの場合と異なり、上記の状態では、mod_securityの設定はされていないようです。そこで、手動で設定する方法を説明します。
/usr/share/doc/mod-security-common にドキュメントとサンプルルール(実体はCRS2.0.3)がコピーされていますので、これを使います。最新のCRSはバージョン2.2.3ですので、サンプルとして導入されるCRSはかなり古いものですが、hashdos対策をする観点からは十分です。また、mod_securityとCRSはバージョン依存があるため、CRSのみ最新のものを入れてもエラーになる可能性が高いのです。最新のCRSを使いたい場合は、最新のmod_securityをソースからビルドしてください。その方法は次回説明します。

まず、/usr/share/doc/mod-security-common/examples/rules 以下のルールを/etc/apache2/modsecurity にコピーします。
# cd /etc/apache2/
# cp -R /usr/share/doc/mod-security-common/examples/rules modsecurity
ルールから logs というディレクトリをログ書き出し用に参照しているので、シンボリックリンクで /var/log/apache2 を指すようにしておきます。
# ln -s /var/log/apache2 logs
Ubuntuの習慣に従い、/etc/apache2/mods-available にmod_securityのconfファイルを作成します。
# vi /etc/apache2/mods-available/mod-security.conf
内容は以下の通りです。
Include modsecurity/*.conf
Include modsecurity/base_rules/*conf
保存した後、a2enmodコマンドでこの設定を反映します。
# a2enmod mod-security
modsecurity_crs_10_config.confというファイルを変更します。
# vi /etc/apache2/modsecurity/modsecurity_crs_10_config.conf
変更内容は以下の通りです。
SecResponseBodyAccess Off ← On から Off にする
これは、レスポンスの中身のチェックをしないという設定です。以上でmod_securityの通常設定は終わりです。

mod_securityの動作確認

次に、mod_securityの動作確認をします。apacheを起動してください。/var/log/apache2以下に、modsec_audit.log と modsec_debug.log ができていれば、正常に起動されています。
まず正常系のアクセスを確認します。以下のURLはサンプルですので、既存コンテンツのURLを指定して下さい。
http://example.jp/index.php
次に、以下がmod_securityによりブロックされることを確認します。既存コンテンツの後ろに、「?union+select」をつけてアクセスします。
http://example.jp/index.php?union+select
403 Forbiddenのエラーが表示されれば、mod_securityが稼働していることになります。

mod_securityのカスタマイズ

次に、hashdos向けのカスタマイズです。再び、modsecurity_crs_10_config.confを変更します。
# vi /etc/apache2/modsecurity/modsecurity_crs_10_config.conf
変更内容は以下の通りです。
SecRequestBodyInMemoryLimit 131072 の後ろに以下を追加する
# 追加
SecRequestBodyLimit 5242880
SecRequestBodyNoFilesLimit 51200
この例では、リクエストボディサイズを5Mバイトに増やし、SecRequestBodyNoFilesLimitを50Kに設定しています。SecRequestBodyNoFilesLimitは、ファイルアップロード以外のPOSTサイズの制限(application/x-www-form-urlencoded形式の場合に有効)なので、hashdosに効果があります。5Mと50Kは、Webサイトの要件にあわせて調整して下さい。

次に、/etc/apache2/modsecurity/base_rules/modsecurity_crs_23_request_limits.conf を修正します。以下の部分を修正します。
# Maximum number of arguments in request limited
SecRule &ARGS "@gt 255" "phase:2,t:none,block,nolog,auditlog,status:403,msg:'Too many arguments in request',id:'960335',severity:'4',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+5,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
変更後の内容は以下の通りです。
# Maximum number of arguments in request limited
SecRule &ARGS "@gt 255" "phase:2,t:none,deny,nolog,auditlog,ctl:auditLogParts=ABDFGH,status:413,msg:'Too many arguments in request',id:'960335',severity:'2',setvar:'tx.msg=%{rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
主な変更点は以下の通りです。
  • パラメータ数が255を超えたら直ちに遮断する
  • ログを取得するが、リクエストボディは出力しない(昨日の記事参照)
パラメータ数上限値255がハードコーディングされているので、Webアプリケーションの正常系のパラメータ数が255を超える場合は、この値を変更してください。
以上でhashdos向けのカスタマイズは終わりですが、昨日の記事同様、hashdos以外のルールを無効にします。本格的にmod_securityを使う(SQLインジェクションやXSS等の対策にも用いる)場合は、以下の作業は省略しますが、その代わりmod_securityの過剰検知を検出して該当するルールを無効化するというチューニングが必要です。

*追記(2012/1/18)
Cookieによるhashdos攻撃が可能であり、上記のルールではCookieによる攻撃を防御できませんので、以下のルールを追加するとよいでしょう。
SecRule &REQUEST_COOKIES "@gt 30" "phase:2,t:none,deny,nolog,auditlog,ctl:auditLogParts=AF
HZ,status:413,msg:'Too many cookies in request',id:'960336',severity:'2',setvar:'tx.msg=%{
rule.msg}',setvar:tx.anomaly_score=+20,setvar:tx.policy_score=+1,setvar:tx.%{rule.id}-POLI
CY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
"@gt 30"がCookie数の上限でハードコーディングされています。適宜変更してください。
(追記終わり)

mod-security.confを修正します。
# vi /etc/apache2/mods-available/mod-security.conf

Include modsecurity/*.conf
### Include modsecurity/base_rules/*conf ← 削除またはコメントアウト
# 以下を追加
Include modsecurity/base_rules/modsecurity_crs_23_request_limits.conf
Include modsecurity/base_rules/modsecurity_crs_49_enforcement.conf
Include modsecurity/base_rules/modsecurity_crs_60_correlation.conf
昨日の記事では、49と60のルールも無効化していましたが、CRSの仕組みをきちんと動かすにはこれらのルールがあった方が良いようですので、残しています。なくてもhashdosに対する保護はできます。

以上の修正の後、apacheを再起動してください。
昨日も書きましたが、mod_securityの副作用の可能性があるので、一通りのアプリケーションのチェックをしておくべきです。とくに、ファイルアップロードが影響を受けやすいので、ファイルアップロード機能がある場合(このエントリが想定しているサイトですが)は、必ずファイルアップロードが正常に動作することを確認してください。

まとめ

Ubuntにapt-get環境でApacheを導入している環境向けに、mod_securityによるhashdos対策の方法を説明しました。
次回は、mod_securityをソースからビルドする方法について説明します。


[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

2012年1月4日水曜日

hashdos攻撃をmod_securityで防御する(CentOS+yum編)

このエントリでは、hashdos対策としてのmod_securityの導入と設定の方法を説明します。CentOS環境でyumによりApacheを導入しているサイトに対して、yumによりmod_securityを導入するというシナリオで説明します。

はじめに

既に当ブログで報告の通り、hashdosと呼ばれる攻撃手法が公表されています。HTTPリクエストのパラメータ名に対するハッシュ値を故意に同一にした(衝突させた)ものを多数(数万程度)送信することにより、Webサーバーを数分程度過負荷にできるというDoS攻撃手法です。まだhashdosによる攻撃事例は報告されていないようですが、既に攻撃コード(PoC)が公表されているため、いつ攻撃が起こっても不思議ではない状況です。
PHPも影響を受けるプラットフォームであり、PHP5.3.9で対処予定となっていますが、まだPHP5.3.9はリリースされていません。また、PHP5.3.9にすぐに移行できないWebサイトも多いことと思います。
PHP5.3.9に移行する以外の対処方法としては以下が考えられます。

  • HTTPリクエストボディ(POST変数)のサイズを数十KB以下に制限する
  • suhosinパッチを導入する。suhosin.post.max_vars(デフォルトは1000)をさらに制限するとなお良し

しかし、利用者に画像などのアップロード機能を提供しているWebサイトなど、上記を実行できないWebサイトも多いと予想します。

そこで対策案として浮上するのがWAFの導入です。WAFでパラメータ数の制限ができる場合、hashdos攻撃を有効に緩和できます。その例として、mod_securityをCentOSにyumで導入し、hashdos対策用に設定する例を紹介します。

CentOSにyumでmod_securityを導入する

CentOSのデフォルトのリポジトリでは、mod_securityはサポートされていません。このため、リポジトリを追加する必要があります。mod_securityの本家では、utterramblingsリポジトリを紹介していますが、CentOS6の対応が不明確でしたので、このエントリでは、CentOS5とCentOS6の両方に対応しているEPELリポジトリを使った導入方法を説明します。
まず、EPELリポジトリを設定します。
# rpm -Uvh http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
CentOS5系とCentOS6および32ビットと64ビットでリポジトリ設定用のURLが異なるので、以下に示します。

CentOS6用
32ビット: http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
64ビット: http://download.fedora.redhat.com/pub/epel/6/x86_64/epel-release-6-5.noarch.rpm

CentOS5用
32ビット: http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
64ビット: http://download.fedora.redhat.com/pub/epel/5/x86_64/epel-release-5-4.noarch.rpm

EPELリポジトリは普段使わないので、デフォルトでは使用しない設定にしておきます。/etc/yum.repos.d/epel.repo というファイルを編集して、[epel]グループの enabled=1 の行を enabled=0 に変更します。
[epel]
...
enabled=0
以上で準備ができましたので、yumでmod_securityをインストールします。先にEPELリポジトリを無効化しているので、以下のようにepelリポジトリを明示してインストールします。
# yum --enablerepo=epel install mod_security
これでmod_securityのインストールは終わりです。CRS(Core Rule Set)も同時にインストールされます。

mod_securityの動作確認

ここで、いったんmod_securityの動作確認をします。apacheを起動し、まずは正常系のアクセスを確認します。以下のURLはサンプルですので、既存コンテンツのURLを指定して下さい。
http://example.jp/index.php
次に、以下がmod_securityによりブロックされることを確認します。既存コンテンツの後ろに、「?union+select」をつけてアクセスします。
http://example.jp/index.php?union+select
403 Forbiddenのエラーが表示されれば、mod_securityが稼働していることになります。監査ログが /var/log/httpd/modsec_audit.log というファイル名で生成されているはずなので、確認しておきます。

ルールのカスタマイズ

次に、mod_securityのルールをカスタマイズします。上記の例(「union select」をブロックする)でもわかりますが、mod_securityに付属するCRS(Core Rule Set)は、やや過剰気味のチューニングになっています。mod_securityにじっくり付き合うのであれば、CRSをまじめにチューニングすればよいのですが、取り急ぎhashdos攻撃だけに対処するのであれば、思い切って他のルールは削除してしまいましょう。
そのためには、以下のようにします。/etc/httpd/conf.d/mod_security.conf を編集します。
Include modsecurity.d/*.conf
Include modsecurity.d/base_rules/*.conf
上記の部分を以下のように変更します(2行目のみ)。
Include modsecurity.d/*.conf
Include modsecurity.d/base_rules/modsecurity_crs_23_request_limits.conf
これにより、HTTPリクエストのサイズ制限のみのルールとなります。XSSやSQLインジェクションは防御できくなくなりますが、目をつぶることにします。

次に、同じファイルの以下の部分を修正します。
SecRequestBodyLimit 131072
リクエストボディの上限が131072バイト(128KB)に制限されています。これを以下のように変更します。
SecRequestBodyLimit 5242880
# 追加
SecRequestBodyNoFilesLimit 51200
上記例では、リクエストボディサイズを5Mバイトに増やし、新たにSecRequestBodyNoFilesLimitを50Kに設定しています。SecRequestBodyNoFilesLimitは、ファイルアップロード以外のPOSTサイズの制限(application/x-www-form-urlencoded形式の場合に有効)なので、hashdosに効果があります。5Mと50Kは、Webサイトの要件にあわせて調整して下さい。

次に、/etc/httpd/modsecurity.d/modsecurity_crs_10_config.conf というファイルを確認します。
## Maximum number of arguments in request limited
SecAction "phase:1,t:none,nolog,pass,setvar:tx.max_num_args=255"
tx.max_num_args=255 は、Webアプリケーションが受け取るパラメータの個数の上限値です。通常はこのままでよいと思いますが、パラメータ数が特に多いアプリケーションの場合は、この値を要件に合わせて増やします。

次に、/etc/httpd/modsecurity.d/base_rules/modsecurity_crs_23_request_limits.conf を修正します。
# Maximum number of arguments in request limited
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,pass,nolog,auditlog,msg:'Too ma
ny arguments in request',id:'960335',severity:'4',rev:'2.0.5'"
        SecRule &ARGS "@gt %{tx.max_num_args}" "t:none,setvar:'tx.msg=%{rule.msg}',setvar:
tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_s
core},setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"
このルールでパラメータ数をチェックしていますが、こままでは単なる警告でブロックしてくれません。このため、1番目のSecRuleにあるpassをdenyに修正しましょう。
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,deny,log,ctl:auditLogParts=ABDFGH,m
sg:'Too many arguments in request',id:'960335',severity:'2',rev:'2.0.5'"
上記では、「log,ctl:auditLogParts=ABDFGH」も追加しました。これは、ログを出力するが、POSTパラメータは出力しないと言う意味です。hashdosのPOSTパラメータは大きくなるので、ログを保存するとディスク容量が圧迫され、一種のDoS攻撃を受けることになるのでPOSTパラメータを除外しています。しかし、研究目的などでPOSTパラメータを保存したい場合は、「ctl:auditLogParts=ABDFGH」の部分を削除して下さい。

現実には、SecRequestBodyNoFilesLimitの方でブロックされるケースが大半だと思いますが、multipart/form-data形式(ファイルアップロードに使われる)でhashdos攻撃される可能性もあるので、上記は必要です。

*追記(2012/1/18)
Cookieによるhashdos攻撃が可能ですので、以下のルールを追加するとよいでしょう。

# Maximum number of Cookies
SecRule &TX:MAX_NUM_ARGS "@eq 1" "chain,phase:2,t:none,deny,log,ctl:auditLogParts=AFHZ,msg
:'Too many cookies in request',id:'960336',severity:'2',rev:'2.0.5'"
        SecRule &REQUEST_COOKIES "@gt %{tx.max_num_args}" "t:none,setvar:'tx.msg=%{rule.ms
g}',setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},setvar:tx.policy_score=+%{tx.notice_anomaly_score},setvar:tx.%{rule.id}-POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

Cookie数の上限はtx:max_num_argsを流用しています。255はCookie数の上限としては大きすぎますが、それほど問題にはならないと思います。しかし、さらに安全を期するには、30などとハードコーディングするか、Cookie数の最大値として別の変数を定義するとよいでしょう。
(追記終わり)


ルールのカスタマイズが終わったので、Apacheを再起動して下さい。
mod_securityの副作用の可能性があるので、一通りのチェックをしておくべきです。とくに、ファイルアップロードが影響を受けやすいので、ファイルアップロード機能がある場合(このエントリが想定しているサイトですが)は、必ずファイルアップロードが正常に動作することを確認してください。

まとめ

CentOSにyum環境でApacheを導入している環境向けに、mod_securityによるhashdos対策の方法を説明しました。
yumを使わないでソースからビルドしている場合や、Ubuntu向けの設定方法も予定しております。

[PR]
hashdosApacheKillerその他、Webサイトのセキュリティ強化策についての相談は、HASHコンサルティング株式会社まで。
安全なWebアプリケーションの作り方DRMフリーのPDFによる電子版もあります。

読者

ブログ アーカイブ