Dec - 22nd
携帯サイトばかり作っているとセキュリティ意識が下がる
Posted at 4:17 pm | Filed Under Security, mobile
暴論ではあるが、実際にそういう事例を見てきたので、ちょっと書きとめておく。
PC向けサイトは、あらゆる攻撃にさらされている。攻撃用スクリプトの実行も非常に簡単で、HTMLのソースには誰でもアクセスできる。URLバーもあって、GETの値を書き換えてみるくらいのことは当たり前に出来る。しかし、携帯サイトでは、以下のような事情もあり、それほどセキュリティについては真剣に対応しなくてもなんとかなってしまう現状がある。
■攻撃者を選ぶサービスである
携帯向けサービスの場合、サイトへのアクセス経路が必ずキャリアのゲートウェイになるので、意図しないアクセスを全てブロックするのは簡単だ。だから、攻撃者はどこかの踏み台サーバからの匿名的なアクセスではなく、何らかの契約情報にひもづけられたアクセスであることを余儀なくされる(パケットの改ざんレベルはここでは問わない)。公式サイトであれば、端末固有のIDが送信されてしまうので、なおさら匿名性は低い。
もちろん、世の中にはありとあらゆる手段で自分の持ち物以外の携帯を手にしている人もいるだろうし、嘘の情報で契約されたものもあるだろう。だが、そんなものを手にしている人たちが、せこせこと月額315円の携帯サイトを攻撃することなどあまり考えられない。普通は、もっと重大な悪事に使うだろう。
したがって、たいていのユーザが容易に自分の身元が割れそうな状態でサイトにアクセスしていることになるので、それほどひどい悪事が行われる可能性はPCと比較するとかなり少ない。
■攻撃が難しいデバイス
どこかで拾った携帯、あるいはとなりの人のをちょっと失敬した端末で攻撃を企てる人がいるとしよう。DoCoMoの携帯だから現在アクセスしているURLを表示できる!喜び勇んで眺めてみると、そこにはどうやら個人情報にひもづくらしいキーと値がセットされている。では、ここを改ざんして他人に成り済ましてみよう!
ところが、PCサイトであればブルートフォース攻撃などちょっとしたスクリプトで簡単にできるのに、アクセス制限のかかった携帯サイトが相手の場合、あの世界的に有名な打ちにくいボタンでせこせこ入力する以外には、ほとんど手段がない。よって、微笑ましいほどの数のパターンしか試すことができないのだ。なんとか工夫したところで、やっぱりたかが知れている。大人数でやればいいのかもしれないが、人を集めるコストと、人数が増えることによる秘密の漏えいリスクを考えると、やっぱり割が合わない。
■Javascriptが使えない
もちろん一部の端末では使えるのだが、基本的にフルブラウザ(TM)でない限りは携帯サイトではJavascriptは利用されない。したがって、Javascriptを起点としたXSSなどの攻撃が意味をなさない。もちろん、サービスの管理画面などPC側の画面では問題になるだろうが、逆にいえばここだけ抑えればなんとかなってしまう。
もちろん、以上の理由から携帯サイトのセキュリティなど無意味だ、というのは間違った考え方ではある。それに、実際には携帯独自のセキュリティホールだって(NDAの壁があって世の中には出回っていないが)当然存在しているので、セキュアなサービスを作るのが一概にPCより楽だというつもりはまったくない。だが、PCの世界では当たり前のように対策していたことが、携帯サイトばかり作っているとついついおろそかになってしまう傾向は絶対にあると思う。
最近、作成中のサービスで某ベンダのセキュリティ診断を受けたのだが、事前対策中に上のようなことを強く思わせる問題がいくつもあった。昔はこんなんじゃなかったのになあ、というのが開発者たちの感想だった。そう、昔はこんなんじゃなかったのだ。HTMLのソースも見られない環境に慣れてしまうと、単純な攻撃に対する意識はどんどん薄れていってしまうのだ。気をつけよう。
Dec - 9th
PHP-5.2.7、5.2.8のZipArchive::extractTo()
Posted at 5:12 pm | Filed Under PHP, Security
Changelogに書かれていないが、標題のZipArchiveの関数に意図しないディレクトリにまで移動できる脆弱性があったのが修正されている。
Zipアーカイブのディレクトリ・トラバーサルというとWikipediaの記事にもある通りUnicodeの問題が有名だが、個人的にはあちこちで名前にRTL制御文字を入れ込んで反転させている男、「ǝunsʇo」を思い出す。
Nov - 30th
WordPress更新
Posted at 4:22 pm | Filed Under PHP, Security, WordPress
2.6.5が出ていたので更新。主な変更点はIPで振り分けるVirtualHostの設定になっているApache2系のサーバでXSS攻撃が可能になる問題の修正。
ここはwp-includes/feed.phpとwp-includes/version.phpを新しくするだけで更新できる。2.6.4は飛ばされて2.6.5がリリースされたことになる。ちなみに2.6.4は今後も絶対リリースされないとのこと。
Oct - 24th
WordPress更新
Posted at 3:31 pm | Filed Under Security, WordPress
変更があったのは以下2つのみ。
1. wp-includes/class-snoopy.php
2. wp-includes/version.php
管理画面の下の方に出ているフィードの取得部分に使われているSnoopyライブラリの脆弱性に対応とのこと。
Sep - 12th
MySQLのカラム複製脆弱性
Posted at 3:45 pm | Filed Under MySQL, PHP, PostgreSQL, Security, WordPress
昨日書いたMySQLの脆弱性ですが、手元の環境で見事に再現しました。MySQLのバージョンはCentOSでyumからインストールしたmysql-4.1.20-3.RHEL4.1.el4_6.1です。
手順は以下の通り。まずデータベース、テーブルを作成します。
mysql> create database sec_test; Query OK, 1 row affected (0.02 sec) mysql> use sec_test Database changed mysql> create table test (username char(16)); Query OK, 0 rows affected (0.01 sec)
ご覧の通り、char(16)でusernameというカラムを持つテーブルを作成します。
まず「admin」というusernameを持つ行を作ります。
mysql> insert into test (username) values ('admin');
Query OK, 1 row affected (0.00 sec)
mysql> select count(*) from test where username = 'admin';
+----------+
| count(*) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
出来ています。
次に、問い合わせの文字列部分の後ろに空白を追加してみます。全部で16文字になるようにしました。
mysql> select count(*) from test where username = 'admin '; +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec)
後ろの空白が無視されているのがわかります。update:正確にいえば、char型なので指定された長さ未満の文字列は空白文字で埋められるみたいです。null文字とかじゃないんですね。
次に、char(16)の範囲を超えたところで「x」を追加して検索してみます。
mysql> select count(*) from test where username = 'admin x'; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
さすがにヒットしませんでしたが、そもそもカラムの制限長を超えているのにエラーにはなりません。
では、この値をINSERTしてみます。
mysql> insert into test (username) values ('admin x');
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> select count(*) from test where username = 'admin';
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.01 sec)
「admin」としてINSERT出来てしまいました。
これで、(1)既存のデータに重複行があるかチェック(2)なければINSERT、という処理で重複登録を防ごうとしてもダメなことがわかります。
ちなみにPostgreSQL 7.4.19でテストすると
db_test=# create table security_test (username char(16));
CREATE TABLE
db_test=# INSERT INTO security_test (username) VALUES ('admin');
INSERT 0 1
db_test=# SELECT COUNT(*) FROM security_test WHERE username = 'admin';
count
-------
1
(1 row)
db_test=# SELECT COUNT(*) FROM security_test WHERE username = 'admin ';
count
-------
1
(1 row)
db_test=# SELECT COUNT(*) FROM security_test WHERE username = 'admin x';
count
-------
0
(1 row)
db_test=# SELECT COUNT(*) FROM security_test WHERE username = 'admin ';
count
-------
1
(1 row)
db_test=# INSERT INTO security_test (username) VALUES ('admin x');
ERROR: value too long for type character(16)
db_test=# SELECT COUNT(*) FROM security_test WHERE username = 'admin';
count
-------
1
(1 row)
db_test=#
INSERTはできません。8.3.3でも。
db_test=# create table test (username char(16));
CREATE TABLE
db_test=# INSERT INTO test (username) VALUES ('admin');
INSERT 0 1
db_test=# SELECT count(*) FROM test WHERE username = 'admin';
count
-------
1
(1 row)
db_test=# SELECT count(*) FROM test WHERE username = 'admin ';
count
-------
1
(1 row)
db_test=# SELECT count(*) FROM test WHERE username = 'admin x';
count
-------
0
(1 row)
db_test=# SELECT count(*) FROM test WHERE username = 'admin ';
count
-------
1
(1 row)
db_test=# INSERT INTO test (username) VALUES ('admin x');
ERROR: value too long for type character(16)
INSERT時にあふれた分が勝手にカットされることはありませんでした。
Sep - 10th
WordPress 2.6.2はセキュリティ修正
Posted at 6:06 pm | Filed Under PHP, Security, WordPress
WordPress2.6.2が出たのでさっそく更新したが、今回のリリースにはセキュリティ関連の修正が入っていた。
PHPのrand関数はlibcのrandのラッパで、mt_randはメルセンヌ・ツイスタ擬似乱数生成装置の実装なのだが、どちらも32ビット型符号なし整数をシードにしている。しかし、実装の問題により実際にはそれ以下の強度にしかならないそうだ。そのため、暗号化に際してこれらの関数を利用するのは不適切ということになる。それに対処したようだ。
MySQLではデフォルトでサーバとクライアント間で送信されるクエリとその応答の長さがmax_packet_sizeディレクティブ(っていうのかな?それはApacheだけ?)で1MBに制限されている。もし1MBを超えたクエリがクライアントから送信された場合、MySQLサーバ側でエラーとして処理してしまう。
たとえば、期限の切れたセッションデータをDBから削除するようなクエリがあり、意図的にこのクエリが長くなるようなデータをセッションに埋め込むことができれば、クエリはいつまでも実行されず、何かしら問題が起きることになる。
update: もっとすごい問題があった。
MySQLにこんなクエリを投げる。
SELECT * FROM user WHERE username = 'admin';
たとえば、ユーザ登録の際に登録名の重複チェックをしているとしよう。WordPressのように、そのサイトにはadminという名のユーザが必ず存在するとして考える。新規のユーザが登録時に「admin」という名前を使おうとすると、上のようなクエリでチェックが行われ、すでに登録されている名前であるとしてアプリケーションによって登録がはじかれる。まあ、そういう仕組みのウェブアプリがあるものと思ってもらいたい。
このusernameというカラムが、たとえばchar(16)だったとする。MySQLではSELECTによる比較時にクエリ内の文字列の後ろの空白は無視されるようになっている。「admin 」だと、
SELECT * FROM user WHERE username = 'admin ';
こうなるが、実際には最初のクエリと同じ扱いになる。
ところで、じゃあ「admin x」という名前を使おうとしたらどうなるだろう。ここでは意図的に名前をchar(16)から外れるようにした。数えにくいかもしれないが、17文字ある。
SELECT * FROM user WHERE username = 'admin x';
MySQLでは、比較の際にはカラムの型を無視してくれるので、上のSQLは何も返ってこない。つまり、新規登録可能なユーザ名として認識される。そこで、INSERET処理を実行すると、今度はカラムの型をみて余分なところはカットし、さらに後ろの空白を取り除くので、あれま、「admin」という名前でユーザ登録が完了してしまう。
これでadminアカウントの乗っ取りが完了する。ひええ。
もちろん、UNIQUE INDEXで対処することは可能だが、そうでないアプリケーションなら困ったことになる。
未検証なのでなんともいえないが、本当だったらこわい。
update:再現しますた。
Jul - 17th
PHPのセキュリティ修正
Posted at 4:59 pm | Filed Under PHP, Security
今朝デスクトップのCentOSでPHPのパッケージがPHP-5.1.6-20.el5_2.1に更新されていたので調べたら、RedHatからセキュリティ関連の更新がかかっていた。
解消されたのは以下の問題:
escapeshellcmdとhtmlspecialchars、htmlentities関数がマルチバイト文字列を正しく扱うことができず、クォート処理を回避されてしまう問題
add_rewrite_var()やsession.use_trans_sidを利用してリンク文字列やフォームに自動的にセッションIDを付与している場合、「ACTION」を含むフォームで外部のウェブサイトを飛び先に指定しているのにセッションIDを付与してしまう問題
fnmatch関数(聞いたことがなかった)で引数の文字数制限がないためオーバーフローを引き起こされる問題
randやmt_rand関数で生成される乱数が予測可能になっていた問題
とのこと。
しかし、BugtraqをみるとPHP-5.3.2以前のバージョンにある不具合だったりするのに、RHEL4のパッチが出ていないのがよくわからない。4.3.9系のパッケージが入っていたような気がするのだが。
May - 2nd
PHP-5.2.6
Posted at 4:29 pm | Filed Under PHP, Security
変更点はこんなかんじ。CVE-2008-0599ってのはPATH_TRANSLATEDの扱いに不具合があって、そこが脆弱性に繋がる可能性がある(参照)とのこと。
Apr - 26th
WordPress 2.5.1
Posted at 7:17 pm | Filed Under Security, WordPress
公表されていないセキュリティ上の問題が修正されたWordPress2.5.1がリリースされている。
うちのサーバはみんな更新した。
Feb - 7th
WordPress更新
Posted at 8:58 pm | Filed Under Security, WordPress
セキュリティ更新。xmlrpc.phpに問題があったらしい。詳細はまだ見ていないが、どうやら第三者に投稿権限が奪取されてしまうようだ。
keep looking »