2015年10月30日
Web認証におけるせめぎ合い – 2人のセキュリティ専門家によるやりとり
本記事は、原著 者の許諾のもとに翻訳・掲載しております。
(訳注:2015/11/1、いただいた翻訳フィードバックを元に記事を修正いたしました。)
成長し続ける様々な脅威に対抗すべく、この10年間でWeb認証システムは進化を遂げてきました。この記事では、架空のWebアプリケーション開発者とアタッカーのせめぎ合いを通じて、最新のセキュリティ技術がどのように様々な脅威に対抗することができるかを提示したいと思います。
以下のやり取りにおいて、ユーザはアタッカーが出現する前に、すでにディフェンダーでいくつかのトラストアンカー(パスワードやハードウェアトークンなど)を正規に確立していることが前提となっています。暗号は、時間や空間にわたって、既存のトラストや秘密を伝達する場合にのみ 使うことができます 。もし、トラストやセキュリティが確立される前にアタッカーがディフェンダーになりすましたとしたら、正規のものを見分けるのは極めて難しいでしょう。また、サイトにはアタッカーがコードを走らせたり、データを読み込んだり、サーバからの認証を解読したりすることが可能な脆弱性(XSSやCSRFなど)が存在しないと仮定します。
-
ディフェンダー: ユーザがユーザ名とパスワードを入力したら、今後は認証済みとして処理されるよう認証クッキーを与えます。
-
アタッカー: ネットワークトラフィックを監視し、回線を流れてくるパスワードを盗みます。
-
ディフェンダー:
<form>
を変更し、HTTPSを経由して送信するようにします。そうすれば、どんなパスワードも読み取ることができません。 -
アタッカー: ユーザがログインページを読み込んだら、能動的な 中間者攻撃 を実行し、バックグラウンドでパスワードがサーバに送信されるようにJavascriptを挿入します。
-
ディフェンダー: ログインページ自体もHTTPSを経由して送信します。これで読み取ったり、変更したりすることはできません。
-
アタッカー: ネットワークトラフィックを監視して、結果として生じた認証クッキーを盗みます。そうすれば、パスワードを知らなくても依然、ユーザになりすますことができます。
-
ディフェンダー: サイトそのものもHTTPSを経由して送信を行い(加えて、クッキーにセキュア属性を付与)、どんなクッキーも見られないようにします。
-
アタッカー: 全てのトラフィック(パスワードやクッキーも)を再度見ることができるように、サイト全体に対して能動的な中間者攻撃を実行し、HTTP経由で送信します。
-
ディフェンダー: HTTPでサイトを読み込まないようにブラウザに伝えるために、
Strict-Transport-Security
ヘッダ を送信します(トラストアンカーを確立するために信頼済み接続で、ユーザがすでにサイトを訪れているという前提)。 -
アタッカー: 中間者攻撃を実行できるように、偽の認証局を見つけるか不正にアクセスするかして、ドメイン名に対する自身の認証を発行してもらいます。そうすれば依然として、HTTPSを送信できます。
-
ディフェンダー: 特定している認証以外でサイトを読み込まないようブラウザに伝えるために、
Public-Key-Pins
ヘッダ を送信します。
この段階で、ブラウザに不正にアクセスしないで、アタッカーが中間者攻撃を実行する妥当な方法はありません。
-
アタッカー: 偽のログインページを作成し、ユーザのパスワードをだまし取ります。
-
ディフェンダー: 2段階認証を設定し、再利用できない2つ目の認証がないと盗んだパスワードが使えないようにします。
-
アタッカー: 2つ目の認証を要求できるように偽のページに書き換え、その認証を使ってすぐにログインします(アタッカーが得られるのはログインセッション一回分だけで、再びログインすることはできませんが、多くの場合はそれだけで十分に悪影響を及ぼすことができます)。
rendering an MITM attack completely unable to use the stolen credential
-
ディフェンダー: 耐タンパー性のハードウェアデバイス 上の秘密鍵によってSMSまたは TOTP の2段階目の認証を置き換えることにより、中間者攻撃によって資格を盗むのを完全に不可能にします(秘密鍵は、サーバからの申し立てに署名するのに使われ、デバイスから離れることはありません)。更に、ブラウザは秘密鍵によって署名された申し立てに、サイトのオリジンを組み込み、その他のどんなオリジンに対してもディフェンダーのサーバ向けに署名された申し立てを送ることを拒否するので、フィッシングの脅威から守ることもできます。これは、ブラウザがアクティブに作動しているからであって、SQRLのような完全なWebベースのソリューションではないから出来ることです。
U2Fデバイスなどの秘密鍵は、フィッシングされることのない認証です。秘密鍵を認証する物理的な所有権を持たない者がフィッシングすることは不可能ですが、ハードウェアデバイスが信頼されていることが前提です。もしアタッカーが認知している秘密鍵のデバイスに取り換えることができるとしたら、全ては無意味です。また、アタッカーが単純にデバイスを盗むという行為から守るためにも、ハードウェアデバイスと併せてパスワードを使用すべきです(デバイスそのものが作動するためのパスワードを必要とするのであれば、それでも構いません)。
-
アタッカー :ユーザをだまして、不当なブラウザ拡張またはデスクトップアプリケーションをインストールさせます。そしてそれを使って、ブラウザのクッキーが保存されているところから、認証クッキーを読み込みます。
-
ディフェンダー :SSL接続を確立するために使った秘密鍵に認証クッキーをリンクさせ、 channel-bound cookies を使います。この方法であれば認証クッキーは、同じ秘密鍵によってサポートされたHTTPSセッションにのみ機能し、アタッカーのコンピュータで使われることを防げます。
-
アタッカー: 秘密鍵や認証クッキーを盗み取るために、コードを書き換えます。これで、私のコンピュータにSSL接続を完全にクローンすることができ、クッキーも依然として使うことができます。
-
ディフェンダー: プロセスや拡張機能が他のソースのセキュリティコンテクストと作用し合うことを許可しないプラットフォームやブラウザを使うようユーザに勧めます。そうすれば、アタッカーの悪意のあるコードはクッキーを読んだり、私のサイトにリクエストを送ったりすることはできません。
アプリケーションレベルの脆弱性(XSSやCSRFなど)はなく、プラットフォーム自体もいかなるアタックに対して完全にセキュアで脆弱性はないもことした想定した場合です。残念ながら、フィッシングできない認証もサポートするようなプラットフォームを知りません。Chrome OSはフィッシングできないの認証をサポートしていますが、拡張機能がローカルにHTTPリクエストを送ってくるのを防ぐ手だてを提供していません。多くの(ルート化されていないデバイス上の)モバイルブラウザは、拡張機能だけでなく、フィッシングできない認証も現在のところサポートしていません。
理論 vs. 実際
理論上は、既述の想定においては、この設計は完全にセキュアです。しかし実際には、状況はそれほど単純ではありません。これらの想定の実現を困難にする問題が多々あったり、他の方法でセキュリティが無効になったりするからです。
ユーザ認証
このテクニックは、ユーザがハードウェアトークンを物理的に保持していることを完璧に証明しようとするものです。しかし、あなたの考えるとおりにハードウェアトークンがあるユーザに属していると確約する助けにはなりません。アタッカーのハードウェアトークンはユーザに属している、と証明されてしまえば、サーバはアタッカーが本当のユーザであるかどうか判断がつかないため、中間者攻撃の展開は依然として可能です。
定義上、ハードウェアトークンを設定しようとしているユーザの認証にハードウェアトークンは使えませんから、標準のHTTPSと証明のピンニングに頼るしかなく、クライアント上での悪意あるコード実行に対しては脆弱なままです。銀行口座のような実体のあるオンラインアカウントに連携させようとしているなら(eメールアカウントのように全く新しいアカウントを作成するのとは反対に)、アカウントを作っているユーザは実際に実体に紐づいており、なりすましや中間者攻撃を試みるアタッカーではないことを証明する必要があります。その最善策は、ユーザ本人が自身を証明し、信頼済みでディフェンダーに制御されたハードウェアを使ってトークンに関連づけすることです。
ハードウェアの信頼性
ユーザのマシン上で勝手なコードを実行できるアタッカーに対抗するのは不可能です(ディフェンダーのサーバは、送信されたリクエストがユーザによる正当なコードからのものか、アタッカーによる不正のコードによるものか区別できないからです)。上述の「完全にセキュア」なシナリオでは、ユーザのプラットフォームはそもそも勝手なコードを受け入れないことになっており、この問題は想定していません。
モバイルプラットフォームでは、他のアプリケーションがブラウザのクッキーや秘密鍵を読むのを防ぐことで、ユーザを証明しようとしています。しかし、完全にこれを強制するのはより困難です。ブラウザ、OS、またはプラットフォームにおいて、何らかのセキュリティ脆弱性(または実際の悪意あるコード)がこの保証を無効にする可能性があるからです。例えば、AndroidやiOSデバイスをルート化あるいは脱獄(またそれによるブラウザまわりの保護の回避)させられるなら、この保証に意味はありません。
この点において踏み込むべきは信頼済みのブートです。WindowsとChrome OSで使われているように、BIOSからブートローダ、OS、ハードウェアドライバまでの全ての実行の流れが、それぞれの起動段階において署名、認証されます。しかし、署名されたコードにおけるセキュリティ脆弱性はなお勝手なコードの実行とマシンを危険にさらすことにつながり得ます。
より大きな問題では(国家レベルのアタックを想定した場合)、ユーザが完全にセキュアなハードウェアを持っていたとしても、アタッカーはそれを、アタッカーが制御するハードウェアに差し替えることもあります。これにはリバースプロキシが含まれており、全てのプロテクトをすり抜けます。ユーザが自身のハードウェアデバイスを承認するシンプルな方法は(四六時中、見張る以外に)ありません。アタッカーは既存のデバイスをこじ開け、全てのデータとプライベートキーをバックドアのデバイスにコピーして、間違いなくユーザ本人の外観、振る舞いに見せかけることができるのです。
(PCBから削除されると自動的に消滅する改ざん防止ハードウェアにサポートされた秘密鍵を構築することはできますが、その改ざん防止策がアタッカーの改ざん策よりも優れているかは、運次第です。またアタッカーがハードウェアの他のパーツをいじり、何も動かさずにバックドアから侵入しないとも限りません)
「パスワードを忘れた場合」
最後に、「パスワードを忘れた場合」は、これらのセキュリティ保証とは完全に正反対の機能です。「パスワードを忘れた場合」機能の趣旨は、ユーザをここまで見たような認証を得ることなくユーザを承認しようということです。つまり、1つ目の課題で述べたようにユーザを最初に関連づける際の問題を再導入することになります。この状況では、アカウント作成とは異なり、常にユーザが何者かを証明する必要があります。なぜなら、ただ新規アカウントを一から作るのではなく、ユーザを既存アカウントと紐づけようとしているからです。
「パスワードを忘れた場合」機能は元々、(暗黙で信頼された)他のサービス、多くの場合eメールに認証を委任することで実行できるものでした。1度目にアカウント作成するとき、ユーザはeメールアドレスを1つ指定します。ユーザはそのメールアドレスに送られたeメールを読むことができるという事実によって承認を行うわけです(大抵、「秘密の質問」など、グレードの低い2つ目の要素が求められます)。しかし、これは新たなリスクを招きます。アタッカーはユーザのeメールアカウント(そして、ほぼ容易な2つ目の要素)をいつでも乗っ取れるのです。更に、ユーザが正当に「パスワードを忘れた場合」を使用した場合でも、クライアント側で既に走っている悪意あるコードに中間者攻撃を行ってアカウントに接続し、汚染すること(例えば、アタッカーの秘密鍵をユーザのそれに追加するなどして)を防ぐ方法はありません。
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa