2014年3月31日月曜日

ANAの個人情報開示請求により1ヶ月間のログイン履歴が確認できた

先日のエントリ「ANAマイレージクラブのログインを少しでも安全にする運用を考えてみたが見つからない」で紹介したように、ANAの個人情報開示手続きにてAMCホームページへのアクセス履歴が開示されるということなので申し込んでおりましたが、昨日封書にて到着しましたので皆様の参考のために公開します。
ますば、送付案内です。


続いて、アクセス履歴。


これを見て、以下の疑問が生じました。

アクセス履歴の項目

IPアドレスについても開示されると思っていましたが、「※IPアドレスにつきましては、社内規定に則り開示をすることは出来かねます。」とありますが、上記の情報だけだと、自分のアクセスなのか、第三者によるものなのかの判別が難しいと考えます。
Yahoo!のログイン履歴にはIPアドレスが表示されます(参考)し、Googleの最近のアクティビティには市区町村までの地域が表示されます(参考)。
表示されるIPアドレスは原則として自分のものであり、仮に自分以外のIPアドレスがあれば、それは不正アクセスであることから、IPアドレスを開示しない合理的理由が分かりません。
ただし、IPアドレスも加えて、上記にある項目は私が例示として示した項目ですので、さまざまな項目を明記すれば、さらなる情報が開示される可能性はあります。

開示期間について

「過去一ヶ月分のアクセス履歴」とあるものの、いつからいつまでの履歴であるのかが分かりません。上記には、3/11~3/15の履歴が表示されていますが、3月16日移行も私はログインをしています。そこで、開示請求書を見直してみると、「ご請求日」の欄が3月15日となっていました。
これで分かりました。「ご請求日」を起点として、過去1ヶ月間のログイン履歴を表示しているということでしょう。
ということは、2月15日から3月10日までは誰もログインしていないということが確認できたことになります。それより前のことは分かりませんが、この期間中には不正ログインは受けていないことが確認できました。

ということで、あまり期待していなかったANAの個人情報開示請求ですが、はなはだ不満は残るものの、当初の目的としていた情報は一応得られたことになります。
なお、AMCサービスセンターに電話で確認したところでは、通常個人情報請求には500円が必要ですが、今回の不正ログインに関しては、例外として、4月末までは無料で対応しているとのことです。
上記の納得のいかない点については、開示請求書の書き方を変えて、昨日再度請求していますので、届き次第報告いたします。

2014年3月28日金曜日

とあるECサイトのアクセス制御不備

商売柄、脆弱性や侵入事件のニュースがあると背景を調べることが多いのですが、このエントリは、侵入されたサイトを見に行って発見した脆弱性のお話です。
とあるECサイトが外部から侵入されたというニュースを見て、再開後のECサイトを見に行きました。普通に会員登録してログインしてみると、セッションIDの他に気になるクッキーが発行されていました(クッキーの名前と値は変えてあります)。
Set-Cookie: login=123456; path=/
Set-Cookie: loginflg=1; path=/
直感的に、login=123456は内部的なユーザID(ユーザ番号)、loginflg=1はログイン済みであることを示すフラグのように思えました。しかし、まさかね。今時それはありえないアルよ。
そこで検証のために、先ほどとは別のユーザを登録してログインしてみました。すると、以下のクッキーが発行されるではありませんか。
Set-Cookie: login=123457; path=/
Set-Cookie: loginflg=1; path=/
なんということでしょう。loginというクッキーが、1つインクリメントされているではありませんか。この段階で、loginの示す値が内部的なユーザID(ユーザ番号)であることは確実のように思えます。
外部に晒す必要のない会員番号を公開している時点で、よろしくない状況ではあるのですが、まだこの段階では致命的な脆弱性であるとまでは言えません。たまに、意味ありげなクッキーを吐いていても実際には使っていなかったり、表示のためだけに使っている場合もあるからです。

そこで、ブラウザのすべてのクッキーを削除した後上記のクッキー(123456等)のみを再セットして、会員情報を表示するページを閲覧してみました。すると、私の個人情報が表示されるではありませんか。次に、loginを123457に変更して個人情報ページを閲覧すると、2番目に登録した方の個人情報が閲覧できました。うーん、これで確定のようですね。クッキーloginの数字を変えるだけで任意のユーザになりすましができてしまいます。しかも、この数字は連番ですので、推測が容易です。

私は拙著「体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践 」にて、自動ログインの危険な実装例として以下の説明を書きました。

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践 P330より引用

引用した箇所は自動ログインとしての説明であり、上記はログイン結果の保持という違いはありますが、「かなり極端な例」として紹介した実装を21世紀の今日、ECサイトのログインで見かけたというのはいささか驚きでした。

では、どうすればよいかですが、読者の皆様には今さら説明する必要もないでしょうが、セッション変数にログインユーザを保持すれば問題ありません。クッキーとは異なり、セッション変数は第三者からも利用者からも変更はできないからです。

ということで、ここから得られる教訓は下記の通りです。
  • 認証後にログインユーザ名を保持するにはクッキー等ではなくセッション変数を使おう
  • 侵入被害にあった後サイトを再開する前に、セキュリティの専門家にチェックしてもらおう
なお、この脆弱性はIPAに届け出を行い、既に修正されていることを確認済みです(取扱い番号 IPA#19289197)。届け出の際の脆弱性は「セッション管理の不備」としていましたが、上記の実装だと「アクセス制御の不備」の方が妥当な気がします。容易に推定できる番号だけで認証状態になってしまうからです。

2014年3月17日月曜日

ANAマイレージクラブのログインを少しでも安全にする運用を考えてみたが見つからない

既に「ANAの不正ログイン事件について徳丸さんに聞いてみた」で書いたように、ANAマイレージクラブ(AMC)のWebサイトに不正アクセスがあり、利用者 9人、計112万マイルがiTunesギフトコードに不正交換されました。ITproの記事を引用します。
ANAに申告があった9人分、計112万マイルについて、3月7~9日の間にiTunesギフトコードへ交換されていたことを確認したという。【中略】同社は10日18時30分以降、iTunesギフトコードへの交換サービスを停止した。不正ログインの手段など攻撃の詳細や、他にも不正ログインがあったかについては調査中という。
ニュース - ANAマイレージクラブへの不正ログインで112万マイルが詐取、住所なども閲覧可能に:ITproより引用
攻撃があってから一週間たちますが、まだANAに申告があった利用者の被害しか発表されていません。上記9名以外にも、マイル不正交換があった可能性はありますので、AMC利用者の方は一度確認をお勧めします。
さらに、不正交換はないものの個人情報が流失した利用者は相当数あると想定されるものの、攻撃者が単に不正ログインして、個人情報を閲覧されただけでは、利用者には確認の手段がありません。

ANAマイレージクラブ・サービスセンターに電話してみた

では、私のアカウントは大丈夫なのだろうかと、こちらのサイトで案内されていたANAマイレージクラブ・サービスセンターに電話で問い合わせてみました。「私の個人情報は漏えいしてないのですか? それは分からないのですか? 」と問い合わせたところ、上席に替わりますということになり、上席なる方の説明によると、個人情報開示手続きにて、ある範囲のアクセス履歴を開示できるということでした。
電話で聞く限り、開示手続きにて開示される履歴は、マイル交換や個人情報の変更に関するもので、それは敢えて開示請求しなくてもメールにより都度通知されるので、利用者も把握できる情報です。利用者が把握できない情報として、IPアドレスやUser-Agentの情報も開示されるようですが…
一方、単にログインしただけとか、ログインした後個人情報を閲覧しただけでは開示の対象にならないようです。さらに開示の期間は直近の1ヶ月間と説明されました。これでは意味がないなと思いつつ、どのような情報が開示されるのか開示請求をかけてみました。結果については、別途報告したいと思います。

AMCサイトはパスワードの定期的変更の効果が多少ある

先のブログエントリで書いたように、AMCサイトは以下の困った特徴があります。
  • パスワードが4桁数字であり不正ログインの可能性が高い
  • 他者がログインに成功しても、それを利用者が知る手段がない
  • 不正ログインがあってもサイト運営者がそれを検知できていない(実績として)
  • 不正ログインに成功しても直ちに悪用されず、後からマイル交換等の悪用をする動機が攻撃者側にある
最後の項について補足します。先のエントリでは、攻撃者はパスワード収集とマイル交換のフェーズを分けて実行したのではないかという推測を書きました。これに加えて、不正ログインに成功した時点ではマイルは交換の対象になっていないが、数ヶ月後であればマイルが増えていて交換の対象になる可能性があります。すなわち、直ちに悪用しないで、後から悪用する動機が攻撃者にはあることになります。
AMCサイトの上記の特性から、AMCサイトではパスワードの定期的変更が一定の効果を持つことになります。これは、以前「パスワードの定期的変更について徳丸さんに聞いてみた(2)」で、「理論的には、次の条件を満たすサイトを使わないといけない場合は、パスワードの定期的変更が効果がなくはない」と指摘した通りです。すなわち、
  • 不正ログインの確率が下がる訳ではない
  • 個人情報が漏えいする確率は変わらない
  • 不正ログイン時点でマイルを直ちに交換せず後からマイル交換するという行為を防げる可能性がある
ということで、効果も、確実性も高い訳ではありませんが、一定の効果があることは認めなければなりません。しかし、これは、パスワード定期的変更が一般的に効果があるという証拠ではありません。むしろ、「AMCサイトは、パスワードの定期的変更くらいしか防衛手段がない残念なサイト」である証拠であると私は考えます。

ただし、上記シナリオに限定すると、パスワードの定期的変更よりも効果的な防御策があります。それは、
  • マイルが貯まったら直ちに交換する
という方法です。マイルが貯まるタイミングは利用者が分かるので、パスワードの定期的変更よりも確実です。ただし、「マイルをたくさん貯めてプレミアムなサービスと交換したい」という希望はあきらめなければなりません。たくさん貯まる前に窃取される可能性があるからです。その場合はパスワードの定期的変更も、あまり意味はないかもしれません。マイルが一定量貯まっていれば、その時点で不正交換されてしまうかもしれないからです。

そもそも、マイルの不正交換が心配なのであれば、不正交換があった時点で運営者に申告して補填してもらうことが筋でしょう。ということで、パスワードの定期的変更を推奨するわけではありません。

アカウントロックを試してみた

既に色々なところで書かれているように、AMCサイトにはアカウントロックの仕組みが実装されていますが、何回パスワードを間違えた段階でロックされるかは書かれていません。そこで、実験で試してみました。
自分のID(お客様番号)を固定して、パスワードの方を変えながら試していくと、10回パスワードを間違えた後に以下の画面が表示されました。


この画面は固定のURLのようです。

アカウントがロックされても利用者にはメール通知されないようです。これは問題だと感じます。第三者から攻撃されていることを、利用者は知る術がないことになります。

次に、アカウントロックの解除はどうすればよいでしょうか。具体的な方法は書いてありませんが、上記の画面には、意味ありげに「パスワードを変更される場合はこちらへどうぞ。」と書かれていますので、こちらに従ってパスワードリセットしたところ、アカウントロックも解除されました。これ自体は妥当な仕様でしょう。正当な利用者がアカウントをロックさせてしまうのは、パスワードが分からなくなってしまったからという理由が多そうで、その場合はパスワードリセットすることで、ロックも解除されるという仕様のようです。
なお、パスワードリセットのためには、登録済みメールアドレスでメールが受け取れることと、会員番号、電話番号、生年月日が必要ですので、試してみる方は上記を確認してから…というより、アカウントロックを試す場合は、先にパスワードリセットができることを確認してからの方が無難でしょう。

認証連携を積極活用するという裏技の検討

前にも書きましたが、AMCサイトはGoogle等と認証連携していることを崎村さんから教えていただきました。
「Webパスワードをオフにする機能」は現時点ではないわけですが、facebookの私のウォールでの会話(非公開)で @keikuma さんから以下の指摘をいただきました。非公開の会話ですので、keikumaさんの許可を得て以下に引用します。
これ、ANAに電話したんですが、同一アカウントに対する試行回数の制限は入っているのだそうです。認証連携があるので、試行回数制限でパスワードをロックしたまま、連携認証ができないかなぁと思ったのですが、今、ちょうど出張の準備が忙しくて、ロックされて面倒な事になると困るので、試せていません。
利用者がわざとアカウントロックした状態で、Google等の認証連携でログインできれば、認証連携のみでの運用ができ、2段階認証等も活用できるというアイデアです。このアイデアについても、先にアカウントロックを試したついでに確認してみました。その結果、@keikumaさんの予想(希望)通り、
  • パスワード間違いでアカウントロックされた状態でも、認証連携ではログインできる
ことを確認しました。
ただし、おそらくサイト運営者の意図した使い方ではないと思われるので、以下に書くような副作用も予想されます。
  • アカウントロックされた状態で認証連携でログインできることは、バグとして将来変更になる可能性がある
  • アカウントロックは、利用者が解除しなくても、一定期間経つと自動的に解除される可能性がある
  • あまりに長期間アカウントロック状態が続くと、アカウントが凍結される可能性がある
ということで、「こうするとよい」という意味ではなく、あくまで調査結果の報告という形でみなさまの参考情報として紹介します。
【追記】公開直後に気づきましたが、意図的にアカウントロックしておいて、使う時はパスワードリセットして使う(認証連携が使えればそちらを使う)という運用はありそうです…が、パスワードリセットしてサイトを使った後は再度アカウントをロックしなければならず、「怪しい行為」として疑われるかもしれません。疑われないにしても、自動的にアカウントロックが解除される可能性はあり、その場合は、この運用は難しいといえます。

まとめ

AMCサイトのログインの仕様について調査した内容を以下にまとめます。
  • AMCサイトのアクセス履歴は個人情報開示請求にて一定の内容が開示される
  • AMCサイトはパスワード10回間違いでアカウントロックになる
  • アカウントロックのメール通知は来ない
  • アカウントロックはパスワードリセットによりロック解除される
  • アカウントロックされた状態でも認証連携ではログインできる
  • 意図的にアカウントロックを活用した裏技があるが、推奨するわけではない
  • 特定の利用者を狙ったパスワード攻撃が成功する確率は 0.1% であり、この確率を減らす方法は(裏技は別として)利用者にはない
  • 不正ログインから時間をおいてマイルを窃取する攻撃に対してはパスワードの定期的変更が一定の効果があるが、もっと良い方法はマイルが貯まったら直ちに交換すること
ANAに対する要望は以下の通りです。
  • 不正ログインの全容(被害者の数など)を早く公開して欲しい
  • 不正ログインされた利用者には個別にその旨を連絡するか、不正ログインの有無を確認する機能を実装して欲しい
  • ログイン通知機能やログイン履歴閲覧機能を実装して欲しい
  • アカウントロックのメール通知を実装して欲しい
  • パスワードの仕様をすぐに変更できない場合は、パスワード認証の停止などの代替策を早期に実装して欲しい
  • パスワードの仕様を安全なものに変更して欲しい

ANAのサイトは、心配だから使わないということは難しいわけで、一利用者として早期の改善を希望致します。

2014年3月14日金曜日

徳丸本Kindle版が半額(1,400円)となるキャンペーン始まりました

拙著「体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践」のKindle版が、本日から2週間、半額の1,400円でお買い求めいただけるキャンペーンが始まりました。

参考: 【電子書籍】4社共同IT書キャンペーン実施!
※キャンペーンはAmazonのKindleのみで実施しています。
※キャンペーンは2014/3/27まで実施の予定ですが、都合により早めに終了することがあります。
徳丸本電子版をまだお持ちでない方は、この機会に購入をご検討ください。

ただし、徳丸本電子版は、Kindle版以外にPDF版もあります。PDF版の割引キャンペーンはありませんが、Kindle版に対して下記のメリットがあります。
  • DRMフリー
  • 検索が可能
  • PC、Macなど様々な端末での閲覧が可能
  • 印刷、コピペ等の制限解除
  • 将来にわたる閲覧の保証
Kindle版に関しては、下記の注もお読みください。
※この商品は固定レイアウトで作成されており、タブレットなど大きなディスプレイを備えた端末で読むことに適しています。また、文字列のハイライトや検索、辞書の参照、引用などの機能が使用できません。
とにかく安いものが欲しい、あるいはKindleでぜひ読みたいという方はKindle版を、通常価格でもPDF版のメリットが欲しい方はPDF版を購入されるとよいと思います…が、最終的に読者の判断で決めていただければと思います。
皆様のご愛読に感謝申し上げます。ありがとうございました。

PDF版の購入はこちら
Kindle版は購入はこちら

2014年3月13日木曜日

ANAの不正ログイン事件について徳丸さんに聞いてみた

高橋: こんにちは、高橋です。先月に引き続き徳丸さんをお招きして、今度はANAの不正ログイン事件についてお話を伺います。徳丸さん、よろしくお願いします。

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

高橋: まず、事件の概要を説明します。「ANAマイレージクラブ」のWebサイトに不正ログインがあり、顧客9人のマイレージ、総計112万マイルがiTunesギフトコードに勝手に交換されていたとするものです。当初顧客の通報で発覚した点はJALの場合と同じですね(参考)。

徳丸: で、私はなにをしゃべればいいのですかね。お招きいただいたので出てきましたが、パスワードがJALは数字6桁、ANAは4桁ですが、それ以外はあまり変わらないのですよね。

高橋: JAL、ANAと事件が続きましたが、攻撃手口は見えてきていないのでしょうか?

徳丸: 公式発表も報道もあまり情報がないので確定的なことは言えないのですが、最近気づいたことがあります。

高橋: それそれ、教えて下さいよ。

徳丸: パスワードを狙った攻撃というと、パスワードが分かったらすぐに悪用すると思いませんか?

高橋: はい。違うのですか?

徳丸: 違うかもなと思い始めたのです。悪用するとバレやすくなりますから。

高橋: 結局ばれるんじゃないのですか? 今回も発覚はしていますよ。

徳丸: はい。ですが、最初の一人でばれると、悪人のもうけが減るじゃないですか。

高橋: はー。すぐ悪用しないとすると、どうだったと推測されますか?

徳丸: JALとANAの事件では、以下のプロセスが必要ですが、1と2は続けてやるとして、攻撃対象のアカウントをためておいて、3は後でまとめて実行した可能性があります。

  1. ログイン画面でパスワードを試行する
  2. ログインできたユーザのマイルの残高を確認する
  3. マイルを悪用する

高橋: 続けて実行するのとどう違いますか?

徳丸: 今回の事件でも、利用者からの通報で発覚しましたが、不正ログインしてマイル残高を確認するまでであれば、利用者は不正を知る術がないのですよ。

高橋: そういえば、そうですね。私のアカウントは大丈夫かしら。

徳丸: ひょっとするとログインまでは成功していて、マイルが少ないから何もされていないだけかもしれませんね。

高橋: あら、どうしましょ。パスワードを変更した方がいいかしら?

徳丸: まだ変更していないのですか?

高橋: だって、数字4桁のパスワード変更しても無意味、みたいなツイートが多かったし…

徳丸: それはきっと、パスワードを変更しても安全になるわけではないという意味でしょう。現に攻撃が起こっていて、パスワードがばれているかもしれないので、パスワードを変更することで、パスワードがばれていない状態にする、という意味はあります。

高橋: そうなのですか。ANAのサイトには、「会員の皆様に安心してサービスをご利用いただくため、AMCのパスワード変更のお手続きをお願いいたします」と書かれていた。ので、「パスワードが数字4桁のままで、どう変えたら安心できるの? ぷんぷくり~ん」と怒っていました。

徳丸: お怒りはごもっともですが、パスワードを変更する意味はあります。

高橋: 分かりました。それでは、パスワードの試行と悪用を分ける意味をもう少し詳しく説明いただけますか?

徳丸: はい。数字4桁のパスワード(暗証番号)とはいえ、パスワードの試行には、それなりに時間が掛かると思うのですよ。

高橋: どれくらい掛かりますか?

徳丸: それは分からないのですが、想定をおいて計算をしてみましょう。

高橋: お願いします。

徳丸: 現時点で悪用されたアカウントは9人ですが、ログイン成功したアカウントはずっと多いと予想されます。

高橋: 何故でしょうか?

徳丸: 奪われたマイル数が多いからですよ。9人で112万マイルということは、1人あたりの平均では12.4万マイルですよ。

高橋: それはすごいですね。私なんか、先日東京~札幌往復しましたが、1020マイルしか貯まってません。

徳丸: そういう利用者が大半だと思うのですよね。

高橋: それでは、マイル残高の多い利用者を狙ったということですか?

徳丸: はい。マイルを盗むと発覚の可能性が高まるので、マイル残高の多い利用者を一気に狙ったと予想します。

高橋: あー、なんか頭いい感じですね。

徳丸: パスワードがばれた利用者数はわかりませんが、ここでは300人と仮定しましょうか。パスワード試行1回で正答する確率は1万分の1ですから、単純計算で300万回パスワードを試行した計算になります。

高橋: 数字がぶれる要素はどこでしょうか?

徳丸: 300人というのは根拠がありませんし、「1234」など利用者がつけそうな暗証番号を狙うと、もう少し確率は上がるでしょう?

高橋: えっ、1234はつけられるのですか? JALの時は、123456は禁止されていましたよね。

徳丸: はい。この画面を見て下さい。これは、ANAマイレージクラブのパスワード変更画面です。

高橋: パスワードの例として「0123」とありますね。

徳丸: これ、本当に0123にセットできるんです。1234もいけますよ。

高橋: ぎょえー

徳丸: ですが、300人の根拠もありませんので、そのまま計算を進めます。ログインの監視もあるのでむやみに試行のスピードがあげられないので、1秒間に1回パスワードを試すとすると、300万秒、すなわち約830時間で、これは約35日間です。

高橋: 35日間も監視でばれなかったのでしょうか?

徳丸: 元々利用者の多いサイトですし、リバースブルートフォース攻撃などで、かつ試行に用いるIPアドレスを分散すれば、監視は相当困難でしょうね。

高橋: あれ、JALの時も、そうだった可能性ありません?

徳丸: そうなんです。不正ログインのIPアドレスは単一だっという報道がありましたが、それ以前のログイン試行の時はIPアドレスを分散していて、悪用の際は単一のIPアドレスだった可能性はありますね。前回は、「JALは監視してなかったのでは?」なんて言ってしまい、すみませんでした(_ _)

高橋: 徳丸さん、憶測でものを言うときは気をつけないと。

徳丸: 面目ないです。

高橋: ともかく、ゆっくり時間を掛けてパスワードを収集して悪用は一気に実行した、というのが徳丸さんの推測なのですね。

徳丸: はい。もちろん根拠はありませんが、攻撃方法としては合理的だと思います。

高橋: 対策はありませんか?

徳丸: あります。JALの場合も、ANAの場合も、攻撃発覚は利用者の通報でしたよね。

高橋: はい。

徳丸: なので、利用者に攻撃を早期に伝えるという施策が有効です。

高橋: 具体的にはどのようなものでしょうか?

徳丸: ログイン履歴の表示とか、ログイン通知メールの送信ですね。

高橋: それを実施しているサイトはありますか?

徳丸: Yahoo!ジャパンがそうですね。こちらの「ログインアラート」と「ログイン履歴」が該当します。

高橋: 徳丸さん、Yahoo!のログインについては以前批判していませんでしたか?

徳丸: こちらの記事でしょうか? これはパスワードリセットに用いる「秘密の質問と回答」に関するもので、アカウントの保護全般に関しては、Yahoo!の機能は素晴らしいですよ。だから、なおのこと、残念だということで。

高橋: そうだったのですね。

徳丸: はい。JALもANAも、ログイン通知の機能があればもっと早期に発覚しただろうし、被害もずっと小さくなった可能性があります。

高橋: あー、それにしても、私のアカウント大丈夫かしら。

徳丸: とりあえずパスワードは変えましょうよ。そして、ログイン履歴の機能は早期に実現して欲しいですね。

高橋: それよりも、パスワードの仕様を変えて、もっと安全なものがつけられるようにすることが先決ではありませんか?

徳丸: ごもっともですが、大規模なシステムなので、パスワードの仕様を変えるとなるとオオゴトですよ。それはそれでやってもらうとして、緊急対処としてできることは早期に実行して欲しいです。

高橋: 他に実施できるものはありますか?

徳丸: あります。崎村さんから教えていただいたのですが、ANAはGoogle等と認証連携しているのですよ。

高橋: Googleでも認証できるということで、4桁暗証番号でもログインできると意味ないのでは?

徳丸: はい。なので、崎村さんが書いておられるように、パスワード認証を無効にする機能を追加できれば、Google等の2段階認証の機能を活用できることになります。

高橋: それはいいですね。

徳丸: ということで、タテマエ論としてはパスワードの仕様を早くなんとかしろというのは要求しつつ、すぐにできる対処もあるので回避策を早急に実施して欲しいですね。

高橋: ありがとうございました。これで、ANAの不正ログインに関する徳丸さんへのインタビューは終わりです。みなさま、ごきげんよう~

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


2014年3月11日火曜日

cheeers! のオープンリダイレクタ脆弱性が修正された

クラウドファンディングサイトcheeers!にはオープンリダイレクタ脆弱性がありましたが、サイト運営者に連絡したところ修正されましたので報告します。

cheeers! のログイン画面は下記の通りですが、アドレスバーに注目ください。from=というクエリ文字列にURLをパーセントエンコードしたものがついています。


正しいIDとパスワードを入力してログインすると、このfromで指定されたURLに遷移ます。下記は遷移後の画面例です。


以上は正常系の流れですが、それではfrom=に、cheeers! とは無関係のURLを指定したらどうなるでしょうか。たとえば、from=https://twitter.com/HiromitsuTakagi/status/350971098248118272 と指定しておくと、ログイン成功後に下記の画面が表示されていました(現在は表示されません)。
— Hiromitsu Takagi (@HiromitsuTakagi) 2013, 6月 29

これはかなりドキッとしそうです。ひょっとすると、口に含んでいたコーヒーを手許のMacBook Airにぶちまけてしまうという「被害」も想定されますが、被害はこれにとどまりません。以下は、cheeers!のログイン失敗画面ですが、これとそっくりの「偽画面」を用意して、そこに遷移させるという攻撃が考えられます。


すると、大半の利用者はパスワードを間違えたと勘違いして、もう一度正しいID(メールアドレス)とパスワードを入力するでしょう。しかし、これは偽画面なので、IDとパスワードを盗まれてしまいます。その後正規の画面に遷移するので、パスワードを盗まれたことすら気づかないで、利用者は閲覧を続けるでしょう。フィッシングの一種ではありますが、起点となる画面が正規のものなので、注意深い人でもだまされやすいというところが問題です。

私はこの問題に3月7日(金)夜に気づきましたのでメールにて運営に報告したところ、3月10日(月)には状況が変化していました。具体的には、https://twitter.com/.... などのサイトには遷移しないようにチェックが入ったようですが、このチェックは不完全でした。具体的には、以下のようなURLはチェックを通ってしまう状況でした。
  • http://takeo.cheeers.jp.example.jp/
つまり、前方一致検査で、http://takeo.cheeers.jp までを確認していたようですが、正しくは、http://takeo.cheeers.jp/ まで(スラッシュまで)確認しなければ、上記のようなサブドメインを使った攻撃を許してしまうのでした。
この問題に昨夜気づきましたので、再度運営に連絡したところ、今日の午前中には修正されていました。

オープンリダイレクタは比較的よく見かける脆弱性ですので、読者の皆様もご注意ください。

なお、拙著体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践には、4.7.1 オープンリダイレクタ(P184)として、脆弱性が混入する原因や対策方法について詳しく説明しています(宣伝)。

2014年3月10日月曜日

よくわかるPHPの教科書 PHP5.5対応版のクロスサイト・スクリプティング

たにぐちまことさんの よくわかるPHPの教科書がこのたび改版されて、よくわかるPHPの教科書 【PHP5.5対応版】として出版されました。旧版はmysql関数を使ってSQL呼び出ししていましたが、mysql関数がPHP5.5にて非推奨となったための緊急対処的な内容となっているようです。つまり、従来mysql関数を呼び出していた箇所をmysqliの呼び出しに変更したというのが、主な変更点のようで、これ以外はあまり変更点は見あたりません。

既に、Amazonでは、熱烈な読者の方からの詳細のレビューが届いています。
神本御降臨!
言わずと知れたPHPプログラミング書籍のロングセラー。
2010年9月に発売された前作の改訂版。
PHPのバージョンも最新の5.5に対応、内容は前作と殆ど同じ。
少し前に前作を購入した方も本書を購入した方がいいでしょう。
【中略】
それにしても、帯の「3万人に読まれた定番の入門書が・・」では、この偉大な書籍にしては謙遜している気が。
せめて「3万人に愛された伝説の入門書が・・・」とか「3万人の運命を変えた史上最強の入門書が・・・」と
書いても良いのではないでしょうか。
プログラミングの入門書でこれだけ支持・絶大な人気の書籍は他にないのですから。
引用元
たにぐちさんの人気はすごいなぁとあらためて思いながら読んでいると、意外にも私の名前もありました。
どうも、現役のバックエンドエンジニア達の反応や評価がよくわからない・・・
どう思っているのでしょうか?気になるところです。
(購入者自身が納得すれば良い話なので、意味がないかもしれませんが)
また、改訂版の本書に対して徳丸先生からの書評も待ちたいところです
召喚されてしまいましたw

まだ網羅的には調べ切れていませんが、現時点で1箇所興味深いクロスサイト・スクリプティング(XSS)を見つけましたので紹介します。

XSSをどうやって見つけたか

私は脆弱性を見つける際には、ソースを見るよりも先に動かしてみることが多いのですが、この脆弱性はソースのgrepで見つけました。サンプルソースをダウンロードして、以下のgrepコマンドの結果を眺めました。
$ grep -r echo *
すると、1箇所HTMLエスケープしていない箇所がありました。
part5-2_sample/join/check.php:        <img src="../member_picture/<?php echo $_SESSION['join']['image']; ?>" width="100" height="100" alt="" />
$_SESSION['join']['image']をエスケープしないで表示しているので、この時点で「局所的にXSSが存在」と言って良いかと思います。

攻撃経路はあるか?

しかし、セッション変数がインプットですので、攻撃経路があるかどうかを確認して見ましょう。この変数は下記でセットされています(part5-2_sample/join/index.php)。
// 画像をアップロードする
$image = date('YmdHis') . $_FILES['image']['name'];
move_uploaded_file($_FILES['image']['tmp_name'], '../member_picture/' . $image);

$_SESSION['join'] = $_POST;
$_SESSION['join']['image'] = $image;
利用者がアップロードしたファイルのファイル名がソースになっていますね。
「ファイル名なのでHTMLエスケープしない」という例は割合見かける気がします。その背景として、以下の心理があるのかもしれません。
  • ファイル名には「<」や「>」は使えないのでXSSはできない
  • ファイルアップロードのフォームではファイル名を外部から指定できない
しかし、これらはいずれも正しくありません。
まず、Unix/Linux/Mac OSではファイル名として「<」や「>」を使うことができます。それに、「<」や「>」を使わないXSS攻撃も可能です。
また、ファイルアップロードのフォームにてファイル名を外部から指定することもできます。これについては、下記のエントリを参照下さい。
ということで、このXSSは攻撃経路がある、ということになります。

実証

このXSSが発現することを以下のPoCで確認しました。JavaScriptはXMLHttpRequest Level2を利用してファイル名を " onerror=alert(document.cookie) gif にセットしています。そして、末尾近くのiframe要素で、XSSのあるcheck.phpを呼び出します。
<body>
<script>
  // 以下は送信するHTTPリクエストボディの中身
  // \n\ は改行(\n) と 継続行(行末の\)を示す
  data = '\
----BNDRY\n\
Content-Disposition: form-data; name="name"\n\
\n\
e\n\
----BNDRY\n\
Content-Disposition: form-data; name="email"\n\
\n\
e@example.jp\n\
----BNDRY\n\
Content-Disposition: form-data; name="password"\n\
\n\
pass\n\
----BNDRY\n\
Content-Disposition: form-data; name="image"; filename="\\" onerror=\'alert(document.cookie)\' gif"\n\
Content-Type: image/gif\n\
\n\
GIF87a\n\
----BNDRY--\n\
';

  var req = new XMLHttpRequest();
  req.open('POST', 'http://example.jp/join/');
  req.setRequestHeader('Content-Type', 'multipart/form-data; boundary=--BNDRY');
  req.withCredentials = true;
  req.send(data);
</script>
<iframe src="http://example.jp/join/check.php"></iframe>
</body>
生成されるimg要素は下記となります。src属性が「"」で閉じられ、onerror属性(イベント)が定義されています。
<img src="../member_picture/20140310092527" onerror='alert(document.cookie)' gif" width="100" height="100" alt="" />
画面は下記となり、確かにセッションクッキーが読み取られています。



対策

ここまで読んだ読者の中には、「こんなに高度な攻撃のことまで考慮しなければならないのか」と疑問を持った方がおられるかもしれませんが、そうではありません。攻撃経路があるかないかに関わらず、淡々と、HTML出力時にエスケープ処理を入れるだけで対策は終わりです。

すなわち、「高度なことを考慮する必要がある」ということではなく、「中途半端に高度なことを考えてしまったので対策漏れが生じた」と言えます。

この脆弱性は、攻撃には高度なワザが必要だが、対策は平凡、というありがちな例と言えるでしょう。局所的な対策をもれなく実施することが重要です。

2014年3月6日木曜日

Windows版PHPのbasename関数がドライブレターを除去しない問題はPHP5.4.25/PHP5.5.9で改修された

以前、「Windows版PHPのbasename関数はドライブレターを除去しない場合がある」にて、Windows版PHPのbasename関数が c:autoexec.bat などに対してそのままの文字列を返す(ドライブレター c: を除去しない)問題を報告しました。
この問題をBug #66395として報告したところ、PHP5.4.25 / PHP5.5.9にて改修されました。これらのリリースは約1ヶ月前で、そろそろ次のバージョンがリリースされますが確認が遅れておりました。
具体的には、数の左側の入力に対して、矢印の右側の結果となります。

bbb/c:autoexec.bat    → autoexec.bat
bbb/cc:autoexec.bat  → cc:autoexec.bat
c:bb/autoexec.bat     → autoexec.bat

2番目の結果に違和感のある方がおられると思いますが、これはNTFSのストリームという機能に対応したものです。ストリームについては下記を参照下さい。


当初は、1番目の例も(ストリームの書式として)c:autoexec.bat と変換されていましたが、私から追記として指摘(PHPはNTFSストリームに対応していないし、パストラバーサル対策としてはまずいよ)したところ、いやいやPHPはNTFSストリームに対応しているよ(私の確認不足でした)という返答でしたが、最終的に、コロンの前(こちらがファイル名で、コロンの後ろがストリーム名)が一文字の場合は除去するというアドホックな仕様に落ち着いたようです
個人的には、NTFSストリームはExplorer等のWindows標準ツールでも上手く扱えないものを認めても混乱の元となるだけだと思いますが、まぁ独自のこだわりがあったのでしょう。最終的な仕様は許容できるものだと思います。

ということで、Windows版PHPをお使いの方は、最新のPHPにバージョンアップを推奨します。ただし、PHP5.3の最新版5.3.28では、この問題は直っていません。

また、アプリケーション側では、basename関数を通すだけでなく、「安全なウェブサイトの作り方」にあるように、「固定のディレクトリを指定」するようにしてください。そうすれば、basename関数のBug #66395の影響を受けなくなります。

2014年3月4日火曜日

正規表現によるバリデーションでは ^ と $ ではなく \A と \z を使おう

正規表現によるバリデーション等で、完全一致を示す目的で ^ と $ を用いる方法が一般的ですが、正しくは \A と \z を用いる必要があります。Rubyの場合 ^ と $ を使って完全一致のバリデーションを行うと脆弱性が入りやすいワナとなります。PerlやPHPの場合は、Ruby程ではありませんが不具合が生じるので \A と \z を使うようにしましょう。

はじめに

大垣さんのブログエントリ「PHPer向け、Ruby/Railsの落とし穴」には、Rubyの落とし穴として、完全一致検索の指定として、正規表現の ^ と $ を指定する例が、Ruby on Rails Security Guideからの引用として紹介されています。以下の正規表現は、XSS対策として、httpスキームあるいはhttpsスキームのURLのみを許可する正規表現のつもりです。
/^https?:\/\/[^\n]+$/i
しかし、Rubyの場合、以下の入力が上記正規表現にマッチしてしまいます。
javascript:exploit_code();/*
http://hi.com
*/
確かに、これはすごいワナです。なぜ、このようなことが起こるのでしょうか。その理由は下記の2点にあります。
  • メタ文字 ^ と $ は「行」の先頭と末尾を示す
  • Rubyの正規表現機能は、デフォルトで複数行モードである

^ と $ の意味

Rubyに限らずPerlやPHPでもそうですが、正規表現のメタ文字 ^ と $ は「行」の先頭・末尾を指します。文字列の先頭と末尾を指定する場合は、\A と \z を使用します。

デフォルトで複数行モード

こちらはRuby特有の仕様ですが、Rubyの正規表現は、デフォルトでPerlやPHPのm修飾子を指定したような動作となります。PerlやPHPの場合は、文字列の途中に改行があった場合でも、文字列全体を1行と見なします。一方、Rubyの場合や、PerlやPHPで正規表現の m修飾子を指定した場合は、改行を行の区切りと見なし、複数行として処理します。このため、/^xxx$/ (PerlやPHPの場合は/^xxx$/m )という正規表現は、「xxxに一致する行がある場合にマッチ」となります。
ちなみに、Rubyにも m修飾子がありますが、これはPerlやPHPの s修飾子にあたるもので、メタ文字ドット「.」が改行にマッチするようにする指令です。

先のPoCの場合、2行目に http://hi.com というhttpスキームのURLがあるため正規表現がマッチして、「正しい入力」とみなされたことになります。

XSS以外の脆弱性の可能性

この問題はXSS以外の脆弱性になる可能性があります。
  • SQLインジェクション: 数値の妥当性確認を正規表現で行っていて、"1\nOR 1=1"等の入力が来た
  • メールヘッダインジェクション: メールアドレスの妥当性を正規表現で実施していて、"a@example.jp\nSubject: hoge"等の入力が来た
  • HTTPヘッダインジェクション: リダイレクト先のURLを正規表現でチェックしていて、"http://example.jp/\nSet-Cookie: SESSIONID=ABC"等の入力が来た

どうすればよいか(Rubyの場合)

では、どうすればよいかというと、文字列のバリデーションなどに正規表現を用いる場合、^ と $ を使わずに、\A と \zを文字列の先頭・末尾を示すメタ文字として使用します。私の観測範囲では、Ruby界隈では元々よく知られている内容と思いますが、大垣さんの指摘のように、他の言語からRubyに移ってきた人には落とし穴になりそうです。

PerlやPHPの場合も ^ と $ を避けよう

大垣さんは、先に参照したエントリで「PHPのpreg_*()もmb_regex_*()も文字列データの開始と終端はそれぞれ^と$です」と書いておられますが、正確には、PHPの場合も ^ と $ は「行」の先頭と末尾を示します。大垣さんに限らず大半の方が、正規表現でのバリデーションに ^ と $ を使って完全一致マッチングを指定していますが、これは間違いということになります。
それでは、過去のPHP(やPerl等)のスクリプトが、これが原因で脆弱性だらけになるかというと、そうではありません。なぜなら、PHPやPerlの正規表現のデフォルトは単一行モードであり、文字列の途中の改行の前後で ^ や $ がマッチすることはないからです。

しかし、行の末尾に改行がある場合にも $ は(改行の直前に)マッチしてしまいます。すなわち、以下のPHPスクリプトは 1 (マッチした)を返します。
preg_match('/^[0-9]+$/', "123\n")
一方、以下は 0 (マッチしない)を返します。
preg_match('/\A[0-9]+\z/', "1234\n")
このように、^ と $で完全一致のチェックをしているつもりでも、データ末尾に改行が含まれている場合を見逃してしまうという問題があります。

書籍等の対応

私はRuby関連の書籍はあまり持っていませんが、初めてのRubyを確認すると、^ $ \A \z の意味が正しく説明されていました。これは、まぁyuguiさんなら当然でしょうが。
PHP関連の書籍はほぼ全滅のような気がしますが、PHP逆引きレシピ 第2版 (PROGRAMMER’S RECiPE)は正しい記述があります。第1版の方は間違っておりますので、まだ第1版をお使いの方は、この機に第2版を買いましょう(お勧め)。
追記。プロになるための PHPプログラミング入門も正しい記述です。徹底攻略PHP5技術者認定[上級]試験問題集[PJ0-200]対応には、上記の非常に詳しい解説があります。(追記終わり)
ちなみに、拙著体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践もw…と、これは自分で書いているので当然として、実はこの本を書くためにこのあたりを調べていたのでした。

まとめ

正規表現によるバリデーションをする場合、完全一致を示す目的でメタ文字 ^ と $ が多用されますが、これは間違いであり、\A と \z を用いるようにして下さい。^ と $ を用いた場合、Rubyの場合は脆弱性の原因となりやすく、他の言語の場合でも、データ末尾の改行をチェックできないと言う問題が生じます。

謝辞

正規表現の完全一致に \A と \z を使うべしという知識は、小飼弾氏から教えていただきました。私が、自分のブログエントリ『正規表現で「制御文字以外」のチェック』にて、「Perlの場合末尾の\nがうまくチェックできない」と書いたところ、小飼氏が「regexp - ^$でなくて\A\zを使おう」にて回答下さいました。あらためてお礼申し上げます。ありがとうございました。

フォロワー

ブログ アーカイブ