2014年9月10日水曜日

パスワード定期的変更の効能について徳丸さんに聞いてみた

高橋: こんにちは、高橋です。今日は徳丸さんをお招きして、今話題のパスワードの定期的変更について、本当のところ効果がないのか、その効能についてご説明いただきます。徳丸さん、よろしくお願いします。

徳丸: 徳丸です。いつもはパスワードの定期的変更にはあまり意味がないと主張していますが、今日はパスワードの定期的変更を擁護する立場なんですね。面白そうです。よろしくお願いします。

高橋: まず問題の整理についてです。IPAより9月3日に『「ID・パスワードのセキュリティ対策促進に関する広告等業務」 係る企画競争 』の仕様書(PDF)が公開されました。その仕様書中の行動喚起を促す対策事例の一つに「ID・パスワードは定期的に変更する」 があったので、セキュリティクラスタが騒ぎ出し、その結果かどうかは分かりませんが、9月9日に同仕様書が改定され、パスワードの定期的変更は対策例から削除されました。一連の議論についてはこちらを御覧ください。

徳丸: 高橋さん、最初は、パスワードの定期的変更の『効能』を説明する人選に僕を選ばれたのはどうしてだろうと思っていたのですが、考えてみると、僕は適任かもしれないと思いました。

高橋: ようやく気づいていただけましたか!

徳丸: 遅まきながら(笑い)。僕は、パスワードの定期的変更については批判的な立場ですが、公平な批判をするためには、パスワードの定期的変更の効能についても客観的に把握しないといけませんからね。

高橋: 確かに。

徳丸: しかも、パスワードの定期的変更を主張している人達は、従来、そうすべき理由をはっきり説明してこなかったのです。

高橋: えっ、そうなんですか?

徳丸: はい。説明があったとしても、簡単に論破できるようなものが多かったです。なので、パスワードの定期的変更の効能をそもそも何だろうとずっと考えてきました。私の過去のエントリについてはこちらを参照ください。

高橋: 最初のエントリは6年半前ですか。

徳丸: そうですね。考えてきた結果、パスワードの定期的変更の「効能」は以下の3つだろうと考えます。

  1. パスワード解読防止
  2. パスワードの漏洩後の緩和策
  3. 個人に割り当てられていないIDのパスワード管理の簡便法

高橋: それでは、1からご説明いただけますか? 1はすごく効能がありそうですが…

徳丸: まず前提として、これはオンライン攻撃ではなく、オフライン攻撃を対象にしています。

高橋: オフライン攻撃とは何でしょうか?

徳丸: オフライン攻撃というのは、ネットワークを通じてではなく、攻撃者の手元で攻撃することです。パスワードの場合は、暗号化されたパスワードあるいはパスワードのハッシュ値が漏洩して、それから元のパスワードを求める行為を指します。

高橋: パスワードが漏れちゃった後の話なんですか…

徳丸: そうです。しかし、昔のUNIXでは、それが当たり前だったのですよ。

高橋: え!? それは本当ですか?

徳丸: はい。UNIX系OSには /etc/passwd というファイルがあって、OSにログインしている人であればだれでも参照はできますよね。このファイルにパスワードのハッシュ値が格納されていたのです。

高橋: そうなんですか! passwdというファイル名なのにパスワードが入ってないなと思っていたのですが、昔は入っていたのですね。

徳丸: はい。/etc/passwdはログインユーザであれば誰でも参照できるので、時間をかければ元のパスワードが解読できてしまいます。それで、定期的にパスワードを変えないと現実的にまずいということがありました。

高橋: パスワードを定期的に変更する合理的な理由があった、と。

徳丸: はい。しかし、そもそもパスワードのハッシュと言えども、誰でも見られる状態で保存するのはまずいということになり、今では /etc/shadow など、rootのみが参照できるファイルにパスワードのハッシュ値が入っています。

高橋: 過去にはパスワードを定期的に変更する理由があったが、今はそうではない、と。

徳丸: 1に関してはそうなりますね。

高橋: わかりました。それでは、2について説明をお願いします。

徳丸: 2は、パスワードが「知らないうちに」漏れているかもしれないので、定期的にパスワードを変更すれば、「パスワードが漏れてない状態」になる、というものです。例えば、パスワードを三ヶ月毎に変更すれば、最長でも被害は三ヶ月で食い止められる…ということですが、実はそうとも言い切れません。

高橋: なぜでしょうか?

徳丸: パスワードが知らないうちに漏れていたとすると、パスワード変更後に再度漏れる可能性があります。

高橋: 必ずそうなりますか?

徳丸: そうとは限りません。パスワード漏洩がフィッシングによるものだとすると、二度目のフィッシングには利用者が気づく可能性もあります。また、既に攻撃側が目的を達していた場合、再度パスワードを得ようといないかもしれません。

高橋: なんか、微妙なラインですね。どういうシステムが、パスワードを定期的に変更したほうがよいのでしょうか?

徳丸: 社内ネットワークのWindowsアカウントのパスワードや、メールの(POP3の)パスワード等は、パスワードの盗用に気づきにくいし、長期間にわたって被害がある可能性が高いので、パスワードの定期的変更が有効という局面はありそうです。

高橋: そういえば、Windowsはポリシーでパスワードを強制的に定期的変更させる機能がありますね。

徳丸: はい。パスワード定期的変更懐疑派の筆頭格であるシュナイアー氏も、会社のパスワードは時々変える(You should change your corporate login password occasionally)ことを勧めていますね。

高橋: 徳丸さんも会社のパスワードは時々変えているのですか?

徳丸: いえ、変えていません。

高橋: ガタッ、だめじゃないですか。

徳丸: 私の会社は、私一人しかいないのでPCはほぼスタンドアロンの利用ですよ。リモートログオンできるわけではないので、脅威はほぼマルウェアに限定されますから、パスワード変えても脅威は減らないです。

高橋: なるほど、環境によってパスワード変更の重要度が変わってくるのですね。

徳丸: そうです。だから、インターネット上のPOP3のパスワードは先日変更しました。と言っても、SSLのみ許可しているし、不正アクセスの可能性は低いので、マルウェアの脅威くらいしかないのですが、これはまぁ気分の問題です。

高橋: 気分ですか、その程度の重要性ということですね。そういえば、先ほど、被害の期間が長期間にわたってとありましたが、被害が短期間が終わってしまう場合があるのですか?

徳丸: あります。spam投稿が目的のなりすましや、代表例は不正送金ですね。

高橋: なぜでしょうか? 長期間に渡って不正送金できたほうが、犯人は嬉しいでしょうに。

徳丸: さすがに悪用された側が気づくでしょう。

高橋: さるセキュリティ専門家は、自分のクレジットカードは(利用額が大きいので)20万円くらい不正使用されても気づかないだろうと豪語されていたようですが…

徳丸: そういう方は、パスワードを定期的に変更するより前に、自分の口座を定期的に確認する必要がありますね。

高橋: それもそうですね。

徳丸: しかし、オンラインバンキングでも、法人口座の場合は定期的変更が有効になる可能性がありまして、それが3番の理由になります。

高橋: なぜでしょうか?

徳丸: 法人口座の場合は、口座の管理者が複数いて、複数の人がパスワードを共有している場合があるからです。

高橋: どうして定期的変更になるのでしょうか?

徳丸: 複数の管理者のうち1人が退職したり、異動になった場合、「パスワードを知っていてはいけない」状態になりますよね。パスワードを例えば3ヶ月毎に変えれば、「パスワードを不正に知っている」状態は最長でも3ヶ月で止まります。

高橋: 銀行口座の場合だと3ヶ月でも長過ぎますね。かといって、毎日パスワードを変更するわけにもいかないし…

徳丸: その通りです。幸いなことにもっと良い方法があります。

高橋: なんだ、その方法を教えて下さい。

徳丸: 一番良いのは、担当者毎にアカウントを分けて別のパスワードにすることです。たとえばジャパンネット銀行の場合ですと、「利用者ID機能」というものがあり、同じ口座に対して利用者毎にIDを変えることができます。

高橋: それは素晴らしいですね。担当者が退職したら、その方のIDを解除するか、パスワードを変更して別の人が使えば良いわけですね。他の方のパスワードは変更しなくてもよい、と。徳丸さんの会社でも「利用者ID機能」を使っているのですか?

徳丸: だーかーらー、私の会社は私一人しかいないので、使う必要がありません。

高橋: でしたねー。でも、そういう機能が利用できない場合は、定期的に変更するしかないのでは?

徳丸: いえ、そうではありません。共用のパスワードを知っている人の退職や異動のタイミングでパスワードを変更するべきです。そうすれば、「パスワードを不正に知っている人」をゼロにできるはずです。理論的には…

高橋: 歯切れが悪いですね。

徳丸: 今までの話は、職務上パスワードを知っているはずの人の話ですが、元々パスワードを知っているはずのない人がパスワードを知っている場合に、定期的にパスワードを変更すると、その人の知っているパスワードを無効にできますね。

高橋: しかし、パスワードを知っていてはいけない人がパスワードを知っていること自体が重大な問題だと思いますが…

徳丸: はい。でも現実にはあり得ますよね。サーバー管理者が外出中にrootで作業をしなければならないのに、リモートからログインできないので、同僚にrootパスワードを教えて作業を代行してもらうケースとか。

高橋: はー、教科書的にはだめだけど、現実にはありそうです。

徳丸: なので、元々管理レベルが低い場合は、パスワードの定期的変更がそれなりに有効、ということですよ。言い換えると、パスワードの定期的変更に頼る状態というのは、けっして好ましいことではありません。

高橋: 分かりました。ここまでのお話を一旦整理すると、昔の/etc/passwdにパスワード自体が入っていた時代はパスワードを定期的に変更する理由があったが、今はそうではないこと、同じパスワードを複数人で使う場合にパスワードの定期的変更がそれなりに意味があるが、本来は一人1IDにするか、異動・退職のタイミングでパスワードを変更するべき、ということでした。社内ネットワーク等のパスワードは、環境にもよるが、パスワードの定期的変更がそれなりに有効、ということですね。

徳丸: その通りです。

高橋: 徳丸さんのご専門のWebシステムの話題があまり出てきませんでしたが、Webの場合はどうなんですか?

徳丸: Webの場合でも、パスワード漏洩の影響が長期間にわたって出て、かつ漏洩に気づけないというケースは、パスワードを定期的に変更した方がよい、ということになりますね。

高橋: あれ、パスワードの定期的変更を認めちゃうんですか?

徳丸: 残念ながら…でも、パスワードの定期的変更よりも良い方法がある場合はそちらを使うべきです。

高橋: 例えばどういうものでしょうか?

徳丸: 例えば2段階認証ですね。2段階認証が使える場合は、パスワードを定期的に変更する必要性はほとんどないでしょう。

高橋: 2段階認証に使うトークンを一種のパスワードだとすると、一分毎にパスワードが変わっているようなものですからね。

徳丸: そうです。パスワード漏洩の影響が長期に及ぶアプリケーションというのは、メールとかストレージサービスですね。その種のサービスは2段階認証が普及しつつあります。一方、被害が個人情報漏洩だけというサイトは、パスワードを変更しても被害は軽減できないので、定期的変更にあまり意味がありません。次に、ログイン通知やログイン履歴の機能があれば、不正ログインに利用者が気づくことができるので、パスワードの定期的変更の必要性は薄くなります。

高橋: 定期的にチェックするのも面倒だし、忘れそうですね。

徳丸: そうですね。この点、Yahoo!やLINEがやっているログイン通知は便利ですよ。自分ではなにもしていないのに、「ログインしました」と通知されるので、気づきやすいです。

高橋: でも、ログイン通知を実装しているサイトは少ない感じですね。

徳丸: そうなんです。だから、サイト運営者は、利用者にパスワードの定期的変更を促す前に、2段階認証やログイン通知の機能を実装していただきたいです。

高橋: そうですね。それでは、そろそろまとめていただきますか?

徳丸: はい。結局のところ、パスワードの定期的変更の位置づけとしては下記のパターンがあると考えます。

  1. もっとよい方法がある(例: 二段階認証)
  2. 元々の管理レベルが低い場合の簡便法(例: パスワードを勝手に知っている人がいる)
  3. 社内ネットワークなど不正に気づくことが難しく被害が長期に及ぶ場合の対策

    1と2については、もっとよい管理方法に移行するべきです。3については、パスワードの定期的変更の動機としてはもっともありそうですが、もし本当に高いセキュリティを目指すのであれば、スマートカードログオンに移行するなど、パスワードの定期的変更に頼らないセキュリティ施策を採用するべきです。私が一つお勧めしたいのは、パスワードを三ヶ月おきに変更するような機械的な定期的変更ではなく、パスワード管理のあり方を定期的に見直すことです。たとえば、フィッシングが問題になってきて二段階認証の普及が進んできたら、自分でも二段階認証を使うかどうかを検討する、パスワードリスト攻撃が問題になってきたら、自分でもパスワードの使い回しをしていないかチェックして、是正する、などです。機械的にパスワードを変更することは、意味が無い場合が多いですよ。

高橋: ありがとうございました。パスワード管理を定期的に見直すというのはいいですね。これで、パスワード定期的変更の効能についての徳丸さんへのインタビューは終わりです。みなさま、ごきげんよう。

※注: このエントリはインタビュー仕立ての記事であり、文責はすべて徳丸にあります。高橋は架空の人物です。

2014年9月2日火曜日

Android版KindleにおけるSSLサーバ証明書の検証不備の脆弱性CVE-2014-3908

本稿では、Android版KindleにおけるSSLサーバ証明書の検証不備の脆弱性CVE-2014-3908について、発見の経緯と脆弱性の詳細、起こり得る影響などについて報告します。

発見の経緯

奥一穂さんとfacebook上で会話していて、スマホアプリ等でSSLサーバ証明書の検証をする際に、コモンネームを検証していないアプリの可能性について示唆を受けました。その内容は、奥さんのブログ記事として以下にまとめられています。
Kazuho's Weblog: SSL/TLSライブラリの正しい使い方(もしくは、コモンネームの検証について)
詳しくは上記記事をお読みいただくとして、サーバ証明書の検証の要点としては以下となります。
  • 証明書が信頼された認証局の発行したものであること
  • 証明書の有効期限の範囲内であること
  • サーバ証明書のコモンネームが接続しようとしているサーバと一致していること
これらのうち、コモンネームの検証が漏れているアプリが結構あるのではないかという問題意識に至りました。私は奥さんとの会話の後、そのようなアプリがどの程度あるのか確認してみたくなりました。

しかし、一般にMITMモードを備えたPROXY(Burp Suite、Fiddler等)は、発行元が信頼されていないがコモンネームと有効期限は適切な証明書を発行して返します。下図は、Burp Suiteを用いてIPAのサイトに接続した際の証明書の内容です。発行者がPortSwigger CAとなっていますが、それ以外のコモンネーム(CN)と有効期限は適正です。


このため、Burp Suite等はこの実験の目的には適しません。
ネットでしばらく探してみましたが、適当なものが見当たらなかったため、簡易的なPROXYを自作して試すことにしました。

実験環境

実験の環境は、以前のブログ記事で使用した環境をほぼそのまま使い、Burp Suiteの代わりに自作PROXY(下図のMITM PROXY)を使いました。「被害者のAndroid端末」としては、改造していない(ルート化や証明書の追加をしていない)Nexus 7を用いました。


MITM PROXYには固定のサーバ証明書(正規のもの)が導入されていて、どのサーバーへの接続に対しても、端末との接続にはそのサーバ証明書を用います。このため、ブラウザでこのPROXY経由で接続すると、下記のようなエラーとなります。下図はIPAのサイトにSSL接続しようとした際にiPhone上のGoogle Chromeが表示しているエラーメッセージです。


実験の結果

この状態でAndroid版Kindleを使用すると、通常は通信エラーになります。下図は、サインインの際のエラー表示の様子です。


しかし、テストをしているうちに、Kindleパーソナル・ドキュメントサービスに関しては、上記MITM PROXYにて復号可能な状態でSSL通信をしていることがわかりました。PROXYをBurp Suiteに変更すると通信エラーになるため、証明書のチェックのうちコモンネームの検証がもれていると推測しました。
これはすなわち、この実験で求めていた成果が、意外な大物として釣り上げられたことになります。

下記は、Kindleパーソナル・ドキュメントに対するリクエストの例です。
GET /FionaCDEServiceEngine/FSDownloadContent?type=PDOC&key=FIHKZL674JJEWT…
is_archived_items: 1
currentTransportMethod: WIFI
software_rev: 1141637187
X-ADP-Request-Digest: K+yGNDcBY3j61RPAtEhhbFHEME+sH4Tn550gwjE88v6TE6EYRAu…
Range: bytes=0-
Accept-Language: ja-JP
X-ADP-Authentication-Token: {enc:JfYZXcdve5JIhRIk8Ec9AfFN/2doDyBtfpWsYeFA…
x-adp-alg: SHA256WithRSA:1.0
x-adp-token: {enc:JfYZXcdve5JIhRIk8Ec9AfFN/2doDyBtfpWsYeFAMiImkmQgm3PocVq…
x-adp-signature: IZjXKX5fo1LelIUc0FKNRiaiHt9tDI0b7ZRdXcu3j5ClUmnXvOYBUIi3…
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.2; Nexus 7 Build/KOT49H)
Host: cde-ta-g7g.amazon.co.jp
Connection: Keep-Alive
Accept-Encoding: gzip
以下はレスポンスの例です。生のPDFが返されていることがわかります。
HTTP/1.1 206 Partial Content
Server: nginx
Date: Sat, 01 Feb 2014 09:48:27 GMT
Content-Type: application/pdf
Content-Length: 27318
Connection: keep-alive
x-adp-host: HMKP292P91XQM
Accept-Ranges: bytes
content-disposition: attachment; filename=odawara-tokumaru.pdf; filename*=UTF-8''%6f%64%61%77%61%72%61%2d%74%6f%6b%75%6d%61%72%75.pdf
Hint-Sidecar-Download: 0
Content-Range: bytes 0-27317/27318

%PDF-1.5
%粤マモ
1 0 obj
<</Type/Metadata/Subtype/XML/Length 2885>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:format>application/pdf</dc:format><dc:title><rdf:Alt><rdf:li>odawara-tokumaru</rdf:li></rdf:Alt></dc:title><dc:creator><rdf:Seq><rdf:li>Microsoft アカウント</rdf:li></rdf:Seq></dc:creator></rdf:Description>
<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/"><pdf:Producer>Microsoft® Word 2013</pdf:Producer></rdf:Description>
<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/"><xmp:CreateDate>2014-02-01T17:06:14+09:00</xmp:CreateDate><xmp:ModifyDate>2014-02-01T09:46:44Z</xmp:ModifyDate><xmp:CreatorTool>Microsoft® Word 2013</xmp:CreatorTool></rdf:Description>
</rdf:RDF></x:xmpmeta>【以下略】
なお、レスポンスからPDFデータを取り出したところ、元のPDFと目視レベルで一致していることを確認しました。バイナリでは一致していませんが、Kindleパーソナル・ドキュメントサービス側で加工が入ったと推測します。

この問題の影響

この脆弱性による影響を報告します。
まず、HTTPSリクエストには認証に関する情報が入っていますので、この情報からAmazonへのセッションがハイジャックされる可能性があります。実際にハイジャック可能かどうかまでは追いかけていません。
次に、レスポンスのPDFデータですが、Kindleパーソナル・ドキュメントサービスを利用して、Kindle端末(Android)に機密文書をダウンロードしようとして、それが盗聴されると情報漏洩となります。
しかしながら、例えば空港のフリーWi-Fiなど信頼出来ないネットワークを使って機密文書をKindle端末にダウンロードするというシナリオがどの程度あり得るかというと、絶対にないとは断言できないものの、それほどありそうなシチュエーションとは思えません。
このような状況を考慮して、IPAによる脆弱性深刻度は、「CVSS値 4.0、攻撃条件の複雑さ: 高」としたのだと推測します。私はこの深刻度評価を支持します。

対策

Android版Kindleをアップデート(本稿執筆時点の最新版は4.6.0)することにより脆弱性は解消されます。

アプリケーション開発者がこの問題を確認する方法

アプリケーション開発者が実機テストにてこの問題、すなわちアプリケーションがSSLサーバ証明書のコメンネームを検証しているかどうかを確認するためには、試験用サーバに本番とは別のSSLサーバ証明書(正規のものだがコモンネームの異なるもの)を導入した状態でテストを行い、端末側でエラーになることを確認するとよいでしょう。

まとめ

Android版KindleにおけるSSLサーバ証明書の検証不備の脆弱性CVE-2014-3908について報告しました。たまたまKindleの場合、脆弱性の影響はそれほど大きくないと考えますが、外出先等でよく使う機能に当該の問題があると、大きな影響となります。公衆無線LANを使う機会が多いという方は増えていると思いますが、公衆無線LANが偽AP(アクセスポイント)や事前共有鍵を用いた暗号解読(参照)による盗聴の危険性が常にあることを考えると、SSLによる暗号化が情報漏洩を防ぐ上では重要です。
皆様の開発されるアプリケーションにおかれましても、SSLサーバ証明書のコモンネームの検証ができているか確認を推奨いたします。

2014年9月1日月曜日

安全なウェブサイトの作り方セミナーin 2014 にて講演します

ディーアイエスソリューション株式会社と株式会社ジェイピー・セキュア共催のセミナー「安全なウェブサイトの作り方セミナー in 2014」で講演します。

日時:2014年9月5日(金)14:30~17:10 受付は14:00より
場所:ダイワボウ情報システム株式会社 東京支社1Fセミナールーム(東京都品川区)
費用:無料(申し込みはこちら
講演タイトル:安全なPHPアプリケーションの作り方2014

企業セミナーとしては珍しいと思いますが、安全なアプリケーションの開発方法を説明して欲しいという主催者からのご依頼でしたので、PHPカンファレンス関西2014の講演(45分間)を90分に引き伸ばしたロングバージョンをお話いたします。普段の徳丸の講演よりも入門的な内容で「最低これだけはやってね」というテーマです。
アジェンダは以下の通りです。
  • アプリケーションの脆弱性を対策しよう
    • クロスサイト・リクエストフォージェリ(CSRF)
    • クロスサイト・スクリプティング(XSS)
    • SQLインジェクション
  • プラットフォームの脆弱性を対策しよう
    • PHPの脆弱性対策
    • SNSやphpMyAdminの脆弱性対策
  • パスワードを保護しよう
    • パスワードリスト攻撃の傾向と対策
    • ソルトつきHASHでのパスワード保存
「アプリケーションの脆弱性」の方では、短文投稿サイトに対する「なりすまし投稿」をCSRF、XSS、SQLインジェクションの三種で実演します。
「プラットフォームの脆弱性」とパスワード保護の説明では、PHPの脆弱性とphpMyAdmin(予定)の脆弱性およびパスワードリスト攻撃を用いて、架空のECサイトに対するクラッキングをやってみます。
おっと、もちろん対策方法も…←「も」ではなくてこちらがメインですがw

それでは、よろしくお願いいたします。

※セミナー終了後の抽選会にて、20名の方に拙著「体系的に学ぶ安全なWebアプリケーションの作り方」が贈呈されるそうです。

2014年8月25日月曜日

模倣サイトとして各所から注意喚起が出されているサイトについて徳丸さんに聞いてみた

高橋: こんにちは、高橋です。今日は徳丸さんをお招きして、今話題の『模倣サイトとして各所から注意喚起が出されているサイト』についてお話を伺います。徳丸さん、よろしくお願いします。

徳丸: 徳丸です。よろしくお願いします。

高橋: まず問題のサイトですが、NTT東日本、NTTドコモ、日本銀行、外務省、総務省など様々なサイトを模倣したサイトが見つかっていて、各社、各省庁が注意喚起をしているというものです。詳しくは、北河拓士さんのまとめをごらんください。

徳丸: これ、総務省のサイトだと、http://www.soumu.go.jp.○○○.org/ のように、ドメイン名の先頭が本物と同じだし、中身も同一だしで、見た人がびっくりしたのでしょうね。

高橋: はい。これはパクリのサイトではないのですか?

徳丸: パクリではありません。PROXYサーバーの一種で、元のサイトのアクセスして、その内容をそのまま表示しているだけです。パクリではなく中継ですね。詳しくは、piyokangoさんがサイト運営者に取材した日記を参照ください。

高橋: なんのためにあるのでしょうか?

徳丸: おそらく悪意などはなく、利用者の便宜のためであると推測されます。

高橋: 便宜とはどのような?

徳丸: piyokangoさんの取材によると、運営者は「ロシアのインターネット検閲回避のために開発したプロキシサービスである」としているようですね。

高橋: いま出ている注意喚起は、閲覧によるウイルス感染とか、フィッシング的に個人情報を盗まれるリスクを説明しているようですが…

徳丸: はい。しかし、検閲回避のサービスであるという説明は信じられそうですし、今の時点で大騒ぎするようなものではないですよ。

高橋: なぜでしょうか? 懸念が少しでもあれば、早めに警告した方がよいと思いますが。

徳丸: それがそうでもないんです。まず、このサイトにアクセスする人が一人もいないとしたらどうでしょうか? ウイルス感染や個人情報漏洩は起こると思いますか?

高橋: それはないですね。しかし、今後うっかり閲覧してしまう人がいるから、そういう事故も起きるのですよね。

徳丸: そこです。一般利用者がどのような経路でこのサイトにアクセスするかを考えてみましよう。

高橋: お願いします。

徳丸: このサイトに限らず、一般の利用者が未知の(悪意のある)サイトを閲覧するには、以下の三通りの経路があります。

  1. メールやtwitterなどから未知のサイトに誘導する
  2. 正規サイトと一文字違いなど紛らわしいURLで打ち間違いからアクセスされる
  3. 検索サイトから遷移する

高橋: 順にご説明いただけますか?

徳丸: はい。まず1のメールやtwitterからの誘導ですが、フィッシング等の罠サイトに誘導する定番の手法です。

高橋: 今はなくても、今後そういう誘導が現れるのではないですか?

徳丸: 絶対にないとは言い切れませんが、もしそうしたいのであれば今の段階からサイトを公開して、各サイトから注意喚起など対策されてしまうのは、攻撃側のメリットがまったくないですね。

高橋: それは、単に攻撃者がお馬鹿さんということで、絶対にないとは言い切れないのでは?

徳丸: はい。しかし、このサイトに限らず本物そっくりのフィッシングサイトは絶えず出現しているわけで、その都度サイトをつぶしたり、ブラウザ側のフィッシング対策機能などで対処しているわけです。万一フィッシング等に使われ始めてから対処すればよいでしょう。

高橋: 既に怪しいサイトとして出現しているのですから、今のうちから手を打った方がよいのでは?

徳丸: いやいや、それはキリがないですよ。仮に私が悪い人だったら、〇〇.org が怪しいと見せかけておいて、本番の罠サイトは 〇〇.jp に置きますよ。フィッシングに引っかかるような方は、その程度のひねり方でもひっかかてしまいますからね。

高橋: 徳丸さん……悪い人だったのですね。

徳丸: 仮定の話ですっ。

高橋: ちょっとからかっただけですよw でも、早めに注意喚起することが悪いとはまでは思えませんね。

徳丸: 後で、そうするデメリットが出てきますので、少しお待ちください。

高橋: 分かりました。2番はどうですか?

徳丸: これはタイポスクワッティングと言われる手法で、入力間違いしやすいスペルのドメイン名を取得して、罠に誘導するというものですが、ドメイン名の先頭が一致しているとはいえ、入力間違いで閲覧してしまうとは思えませんね。

高橋: 私もそう思います。それでは、3 をお願いします。

徳丸: メールなどで誘導しないと仮定すると、もっともありそうな流入経路は検索エンジンですよね。

高橋: はい、そう思います。Google検索とかでたどり着くサイトが多いですよね。

徳丸: そうなんです。そうすると、今回の件で該当サイトが話題になり、ブログサイトからリンクされる例が増えると、どんどん検索順位が上がってしまう可能性があるのですよね。

高橋: すると、どうなりますか?

徳丸: たまたま、とある検索キーワードでヒットしたサイトが、問題のサイトである確率が高まるかもしれません。

高橋: そうなんですか? 検索エンジンに登録されないようにrobots.txtが設置してあったりしないのですか?

徳丸: 実はしてあります。すべてのユーザーエージェントに対して「Disallow: /」の指定がされていますが、これはこのサイトの悪意のなさの表れと言えます。しかし、仮に悪意があるのであれば、将来この設定を変えるかもしれませんよ

高橋: どうなりますか?

徳丸: 突然検索サイトの上位に躍り出て、フィッシングなどの悪用に使われるかもしれません。

高橋: やっぱり悪いサイトじゃないですか!

徳丸: いやいや、仮定の話ですよ。言いたいことは、このサイトの悪意を仮定するのであれば、取り上げずにそっとしておいたほうがよいということです。

高橋: 先ほど言っておられた「デメリット」とはこのことですね。

徳丸: そうです。対策するなら、別の形の方がいいです。

高橋: 対策にはどのようなものがありますか?

徳丸: まずはフィッシング一般に向けた対策がいいでしょう。自社のドメイン名を広く告知する、キャンペーン毎にドメイン名を取得することはできるだけ避けて、自社のドメイン名のサブドメインにサイトを集める、予算に余裕があればEV SSLにする、などです。

高橋: そっとしつつ、サイトの内容をぱくられない方法はありませんか?

徳丸: あります。PROXYサイトからの通信を遮断すれば、ぱくられることはありません。詳しくはこちらのサイトの説明をお読みください。

高橋: 分かりました。それでは、最後にまとめていただけますか?

徳丸: はい。問題のサイトはロシアの検閲を回避するために設置されたPROXYサービスであり、現時点で悪意を想定する理由は見当たりません。将来悪意をもつことを想定したとしても、現時点で注意喚起することは賢明とは言えず、そうするデメリットもある、ということですね。

高橋: ありがとうございました。これで『模倣サイトとして各所から注意喚起が出されているサイト』に関する徳丸さんへのインタビューは終わりです。みなさま、ごきげんよう。

※注: このエントリはインタビュー仕立ての記事であり、文責はすべて徳丸にあります。高橋は架空の人物です。

2014年7月7日月曜日

JSON SQL Injection、PHPならJSONなしでもできるよ

DeNAの奥さんと、はるぷさんがJSON SQL Injectionについて公表されています。
上記の記事は、主にPerlスクリプトがJSONデータを受け取るシナリオで説明されています。もちろん、この組み合わせに限定したはなしではないわけで、それではPHPではどうだろうと思い調べてみました。

JSON SQL Injectionとは

以下、はるぷさんの「不正なJSONデータによる…」にしたがってJSON SQL Injectionについて説明します。
Perl向けのSQLジェネレータの一つであるSQL::Makerにおいて、以下のスクリプトを想定します。
my ($sql, @bind) = $builder->select(
    "table_name", ["*"],
    {"name"=>$user_name});
ここで、$user_nameとして 'yamada' を与えると、以下のSQL文が生成されます。
SQL文: SELECT * FROM `table_name` WHERE (`name` = ?)
変数: yamada
$user_nameが外部からJSON形式で渡ってくる場合(APIなどのように)を想定すると、ここの部分のJSONデータが {"key":"value"} となっていると、SQL::Makerは、keyをWHERE句の比較演算子とみなし、以下のSQL文を生成します。
SQL文: SELECT * FROM `table_name` WHERE (`name` KEY ?)
変数: value
ここで、keyの部分は任意の文字列を書くことができ、それが *そのまま* SQL文に流し込まれます。この仕様を悪用すると、SQL文を本来意図しない形に改変できてしまいます。これがJSON SQL Injectionです。


PHPではどうか?

それでは、我らがPHPではどうでしょうか。
@memememomoさんがSQL::MakerをPHPに移植されておられまして(参照)、これを使うと、JSON SQL Injectionが再現できます。
$builder = new SQL_Maker(array('driver' => 'mysql'));
list($sql, $binds) = $builder->select('table_name', array('*'), array('name' => $user_name));
ここで、$user_nameが'yamada'の場合、以下のようにPerl版とまったく同じ結果になります。
SQL文: SELECT * FROM `table_name` WHERE (`name` = ?)
変数: yamada
次に、$user_name = array('key' => 'value'); とすると、生成されるSQL文は下記のとおりです。
SELECT * FROM `table_name` WHERE (`name` key ?)
すなわち、JSONのキーとして指定した値が *そのまま* SQL文に注入されます。JSON SQL InjectionがPHPでも再現出来ました。
ここでは、PHP版のSQL::Makerを題材として使用させていただきましたが、後述するように、他にも同様の挙動をしめすSQLジェネレータを確認しています。

PHPの場合はJSONは必要ない

しかし、上記のスクリプトにおいて、SQLインジェクションを起こすためには、入力値がJSON形式である必要はありません。$user_nameが連想配列(文字列をキーとした配列)であれば良いわけですので、PHPの場合であれば、以下のようにHTMLフォームからでも指定は可能です。
先のスクリプトで、$user_name = $_GET['user_name'] としていた場合、以下のクエリ文字列でスクリプトを呼び出すと…
http://example.jp/query.php?user_name[key]=value
生成されるSQL文は下記となります。
SELECT * FROM `table_name` WHERE (`name` key ?)
このため、keyの箇所に任意のSQL断片を指定することにより、SQLインジェクション攻撃が可能となることを確認いたしました。一例を挙げます。
http://example.jp/query.php?user_name[>''+or+1%3d1)%23]=value
生成されるSQL文は下記となります。
SELECT * FROM `table_name` WHERE (`name` >'' or 1=1)# ?)
PHPの場合、JSONを使わなくてもJSON SQL Injectionができてしまう(*1)ことになり、該当するSQLジェネレータを使っている場合、広範囲のアプリケーションが脆弱になる可能性があります。

*1: この場合、JSON SQL Injectionという呼称は適切でないと考えられます。

対策

PHP版のSQL::Makerについては、対策版が公開されています。本家Perl版と同様に、strictモードが導入されました。memememomoさん、対応ありがとうございます。
これは以下のように使用します。
$builder = new SQL_Maker(array('driver' => 'mysql', 'strict' => 1));
$user_name = array('key' => 'value');
list($sql, $binds) = $builder->select('table_name', array('*'), array('name' => $user_name));
この際の実行結果は下記のように例外が発生します。
PHP Fatal error:  Uncaught exception 'Exception' with message 'cannot pass in a ref as argument in strict mode' in /home/ockeghem/php-SQL-Maker-master/lib/SQL/Maker/Condition.php:52
strictモードが使えない場合は、条件設定に与える引数の型チェックを行う方法があります。
  $user_name = $_GET['user_name'];
  if (! is_string($user_name)) {
    # エラー処理
    exit;
  }

他のSQLジェネレータの状況

SQL::AbstractのPHPへの移植版についても同種の問題があることが分かっています。作者に連絡をとったところ、古く個人的なプロジェクトであり、かつ開発者自身の使い方では strict モードに移行すると過去のスクリプトが動かなくなると言うことで、strictモードの対応は今のところないということでした。元々、ライブラリ側の脆弱性とまでは言えない問題ですので、これは仕方ないと考えます。呼び出し側での対応をするのがよいでしょう。

FluentPDOの場合、任意のSQL断片を注入することはできないようですが、パラメータとして配列を与えることによって、等号ではなく IN 演算子を使うものに変更はできるようです。以下のスクリプトで説明します。
$pdo = new PDO("mysql:dbname=...
$fpdo = new FluentPDO($pdo);  // FluentPDOオブジェクトの生成
$query = $fpdo->from('user')->where('id', $_GET['id']);
まず通常のケースとして、クエリ文字列を ?id=yamada とすると、生成されるSQL文は以下となります。yamadaはバインドする値として指定されます。
SELECT user.* FROM user WHERE id = ?
次に、?id[]=yamada&id[]=sato とすると、生成されるSQL文は以下の通りです。
SELECT user.* FROM user WHERE id IN ('yamada', 'sato')
これにより、特定IDの存在の有無を確認するようなケースでは、一度に多数の候補を試すことができることから、少ないリクエストでの探索が可能になります。


まとめ

SQLジェネレータが生成するSQL文について、PHPを使う場合は、JSONを用いていない場合でも、JSON SQL Injectionと類似の問題が発生する可能性があることを紹介しました。ライブラリの特性・仕様を理解した上で、正しい使い方により、脆弱性の混入を防ぎましょう。

また、私1人の調査には限界がありますので、類似の問題を見つけた方は教えて頂けると幸いです。

2014年4月30日水曜日

三井住友VISAカードのフィッシングサイト

昨日当方に来た以下のメール。メール自体はやる気のないフィッシングという感じでしたので、中身を見てやろうと検証環境を起動しました。閲覧しただけでマルウェアに感染するかもしれませんので…


で表示されたのは、1回リダイレクトして、以下のサイト。デザインが本物そっくり(同じ?)なのは当然として、アドレスバーに注目ください。



ちなみに、本物はこれです。


URLを見ると、

本物: https://www.smbc-card.com/vp/create/create_user.do
偽物: http://www.smbc-card.com.xxxxxx.com/vp/create/create_user.html

ということで、違いは下記の通りです。
  • 本物はEV SSLだが、偽物はHTTP(HTTPSですらない)
  • ドメイン名は、偽物は先頭は同じだが、後ろに xxxxxx.com がついている
  • 拡張子の違い(.do と .html)
筋論から言うと、ドメイン名の見分け方を学習してもらうべきところではありますが、一般の方に理解いただくのは中々難しそうです。ということで、
  • そもそもメールに書いてあるURLは閲覧しない
  • 銀行やクレジットカードのサイトは EV SSL の企業名・組織名を確認する
というあたりが対策としてよいのではないでしょうか。

ところで、twitter上では、メールの電子署名で確認できないかというコメントを頂きました。これは筋としてはよいと思うのですが…
たまたまSMBC VISAからの本物(と思われる)メールが来ていますが、本物にもS/MIME署名はありませんでした。同じSMBCでも、銀行の方はS/MIME署名がされています。

ということで、皆様もお気をつけ下さい。

PS.
拡張子の .do が時節柄気になるところではありますね。

2014年4月11日金曜日

PHP考古学: PHP4.2.xではmb_eregは複数行モードで動作していた

大垣さんのブログエントリに刺激を得て、古いmb_eregの挙動を調査しました。その結果、 PHP4.2.x上のmb_eregは複数行モードで動作していたことが分かりましたので報告します。

前回までのまとめ

正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう」にて、Ruby、Perl、PHPの正規表現では、^ と $ は、「行」の先頭と末尾を示していて、文字列の先頭と末尾を指定するには、\A と \z を使うべきであることを説明しました。そして、Rubyの場合はデフォルトが複数行モードであるので、^○○○$ という形で全体一致検索を指定したつもりでも、簡単にチェックをすり抜け重大な脆弱性に直結します。一方、PerlやPHPの正規表現はデフォルトでは単一行モードであるので、文字列末尾の改行をチェックできないという問題はあるものの、重大な脆弱性に直結するケースはあまりないと考えられることを指摘しました。

古いバージョンのmb_eregはデフォルトが複数行モードだった?

ところが昨日大垣さんの書かれたエントリ「なぜRubyと違い、PHPの正規表現で^$の利用は致命的な問題ではないのか?」には以下のように書かれていました。
実は古いmbregex(忘れるくらい古い4.xの時代の話です)はRubyと全く同じ動作をしていました。この動作はセキュリティ上の問題であるとして、現在の^は\A(データの先頭)と同じ、$は\Z(改行を含む終端にマッチ)に変更されました。
私がPHPに親しむようになったのはPHP5.2以降のことなので、「忘れるくらい古い4.xの時代の話」は知らないのですが、どうしても知りたいと思い調べてみました。
といっても、私の手元にはphpallにて PHP4.4.9とPHP5.0.0以降のバイナリはすべてありますが、それより古いPHPはありません。そこで、この機会に、すべてのPHP4もビルドすることを決意いたしました。phpall完全版とでも言いましょうかw

phall完全版

phpall完全版と言っても、ここからPHPの古いソースをダウンロードしてビルドするだけです。@hnwさんが指摘するように、PHP5の古いバージョンをビルドするのはコツがいります。
実は、PHP 5.0.0-5.0.3はgcc4 でコンパイルできないという問題点があります。gcc4でコンパイルするためには、http://bugs.php.net/bug.php?id=32150 の通り、Zend/zend_modules.h を修正する必要があります。
こんなときgcc3でコンパイルするのも一つの手ですが、MacOSX10.4や10.5ではgcc3が提供されていません。今後このような環境が増えてくるのではないでしょうか。
また、PHP 5.2.0-5.2.3は./configureの途中で下記のように怒られてしまいます。
configure: error: installation or configuration problem: C++ compiler cannot create executables.
原因は追いかけていませんが、autoconfでconfigureスクリプトを作り直すと問題なくバイナリのビルドまで通ります。
phpallコマンドでPHPの全バージョンの挙動を試すより引用
後者のPHP 5.2.0-5.2.3の問題については、独自の調査により新たな知見を得ております。お恥ずかしいことに実験ノートをきちんとつけていなかったので、いつ・どのように発見したかを示す証拠はないのですが、以下のようにg++を導入することにより、エラーなくビルドできるようになります(Ubuntu 12.04LTSにて確認)。
$ sudo apt-get install g++
この方法で、私はこれまでに200回2回ほどPHP5.2.0-5.2.3のビルドに成功しています。まぁ、C++コンパイラが動かないよというメッセージに素直に従っただけということですがw
PHP4については、gccのバージョンが上がりチェックが厳しくなったためにエラーになる箇所が複数ありました。具体的には、static変数をextern宣言している等です。これらは、ソースの方を修正しました。
先のアーカイブにはPHP3.0.18のソースもあったので、ついでにこれもビルドしました。ということで、PHP3.0.18、PHP4全て、PHP5全てを含む「phpall完全版」の誕生です。

試してみる

以下のソースで試してみました。
<?php
  $a = "abc\n123\ndef";
  var_dump(mb_ereg('^[0-9]+$', $a));
実行結果は下記となります。mb_eregが実装されたのはPHP 4.2.0以降なので、該当バージョンのみ示します。
$ phpall mbereg.php
php-4.2.0: int(1)
php-4.2.1: int(1)
php-4.2.2: int(1)
php-4.2.3: int(1)
php-4.3.0: bool(false)
php-4.3.1: bool(false)
php-4.3.2: bool(false)
...
php-4.3.11: bool(false)
php-4.4.0: bool(false)
...
php-4.4.9: bool(false)
php-5.0.0: bool(false)
...
php-5.5.11: bool(false)
php-5.6.0beta1: bool(false)
なんということでしょう! PHP 4.2.xでは、大垣さんの指摘のように、mb_eregが複数行モードで動いていたようです。
PHP 4.3.0でこの仕様は単一行モードに変更されていますが、その理由は、大垣さんの言われる「セキュリティ上の問題」というよりは、eregと仕様を合わせたということではないでしょうか。mb_eregはeregからの移行を想定していると思われますし、mbstring.func_overload = 4 とすると、ereg関数の呼び出しがmb_eregにオーバーロードされるわけで、eregとの互換性は重要です。

この問題による影響と対策

PHP 4.2.xを使っている環境では、mb_eregの全体一致検索に ^ と $ を使っていると、前述のような脆弱性となる可能性があります。^ と $ ではなく、\A と \z を使って全体一致検索を指定するようにしてください…というより、PHP 4.2はとっくの昔のサポートが終了しているので、最新のPHPに移行するようにしましょう。
…と、ここで気になってPHP 4.2がリリースされた時期を調べてみたのですが、
  • PHP4.2.0     2002年4月22日 
  • Windows XP 2001年10月25日(OEM)
いまとなっては化石のようなPHP4.2ですが、リリースされた時期はWindows XPよりも *新しい* のですね。いかに、Windows XPが長くサポートされてきたかをあらためて感じました。

まとめ

大垣さんの指摘に刺激を受けて、古いmb_eregの挙動を調査しました。その結果、PHP4.2.xのmb_eregは複数行モードで動作することを確認しました。
この結果に関係なく、全体一致検索には、\A と \z を用いるようにしましょう。また、PHP4.xを使っているサイト(まだ結構あります)は早急にPHPの最新版に移行しましょう。

フォロワー