先日、あるブロックチェーンプラットフォームの脆弱性をテストしていたKaspersky Blockchain Securityのエキスパートたちは、そのプラットフォームのパスワード復元プロセスがユーザー名列挙による攻撃に対して脆弱であることを発見しました。「ユーザー名列挙攻撃」とは聞き慣れない言葉かもしれませんが、あなたがWeb開発に携わっているのであれば、これがどういうものなのか、どのような危険をもたらすのか、知っておいた方がよいタイプの脅威です。
ユーザー名列挙攻撃とは何か
パスワードとログインIDによる認証を行うWebアプリケーションには、ユーザーデータベースとのやりとりを担うコンポーネントがいくつか備わっています。ログインウィンドウ(必須のコンポーネント)、登録フォーム(ユーザー名の重複を回避するためのもの)、そして、パスワードのリセットページ(対応するアカウントが実在することを確認するためのもの)です。
これが十分安全な形で実装されていないと、Webサイト利用者のデータベース内に特定のユーザー名が存在するかどうかを確認するために、第三者がこれらのコンポーネントを悪用する恐れがあります。要するに、誰かがログインウィンドウや登録フォームなどに対してユーザー名の入力を次々と試し、Webサイトのユーザーデータベースの中にそのユーザー名が含まれるかどうかを確認する可能性があるということです。これが、ユーザー名列挙攻撃です。
かつては、Web開発元がこれらコンポーネントをまったく保護せずに実装するのは普通のことでしたし、ハッキングを仕掛ける攻撃者が使えていたのは、ユーザー名のリストと、ログインフォームに名前を1つずつ自動入力していくプログラムくらいのものでした。やがてWeb開発者たちは、ハッキング防止のために、CAPTCHAの使用、ログイン試行回数の制限、入力内容をアスタリスクなどで隠す、などさまざまな保護手段を採用するようになりました。
こういった保護手段はどれも、今ではWebアプリケーションのログインウィンドウで使われています。しかし、登録フォームやパスワードのリセットページには、保護手段が適用されていない場合があります。さらに、ユーザー名がデータベース内にあるかどうかはサーバーの応答のタイミングで分かるということが、開発側で考慮されていない場合もあります。たとえば、データベースにユーザー名が存在する場合、サーバーから応答があるまでの時間は2ミリ秒です。存在しない場合、応答が返ってくるまでの時間は約4ミリ秒、ほぼ2倍の時間がかかります。この違いは人間にはわかりませんが、ユーザー名列挙を自動で行うツールは簡単に違いを見て取ることができます。
ユーザー名列挙攻撃の危険性
このように、ユーザー名列挙攻撃は、ユーザー名がデータベース内にあるかどうかの確認に利用可能です。確認したからといってすぐにログインできるようになるわけではありませんが、攻撃者からすると、ハッキングに必要な情報の半分が手に入ります。たとえば、総当たり攻撃(ログインIDとパスワードの組み合わせをひたすら試していく方法)を仕掛けようとしている場合を考えてみましょう。ログインID(つまりユーザー名)とパスワードの組み合わせをひととおり試す必要はなく、「データベース内にある」ことが分かっているユーザー名に対応するパスワードだけ試せばよいので、時間と手間が省けます。
また、多くのWebサービスでは、メールアドレスをユーザー名として使います。したがって、一般的に1つのログインID(ユーザー名、この場合はメールアドレス)を多数のWebサイトで使用する人が多いということになりますが、セキュリティへの取り組み具合はWebサイトによって濃淡があります。ログインIDとパスワードの組み合わせが漏洩したという話がしょっちゅう報じられますが、このようにして漏洩したデータは、ハッカー向けの掲示板でまとめて売りに出されています。また、複数のWebサイトで同じパスワードを使い回す人が少なくありません。そこで考えられるのは、たとえばこういう筋書きです。どこかの攻撃者が、あるユーザー名があなたのWebサイトに存在するのを確認する。続いて攻撃者は、闇サイトで入手した漏洩データの中にそのユーザー名が存在するかどうか確認する。ユーザー名が見つかったら、このユーザー名に対応するパスワードを漏洩データの中から確認。見つかったパスワードをそのユーザー名と組み合わせて、あなたのWebサイトにログインを試みる。
さらに、スピアフィッシング(標的を絞ったフィッシング)を仕掛けようとする人物が、偵察の段階でユーザー名列挙攻撃を仕掛けることもよくあります。たとえば、標的があなたの運営するWebサービスにアカウントを持っていることを確認すると、攻撃者はあなたの会社が発信元のように見える偽メールをその人に送り、パスワードの変更を呼びかけ、あなたの会社のWebサイトによく似たフィッシングサイトへ誘導します。メールを信じたその人がそのサイトで新しいパスワード設定しようとすると、確認のためとして古いパスワードも入力させられます。このようにして、攻撃者は欲しい情報を手に入れるのです。
ユーザー名列挙攻撃からの保護を講じるには
パスワードのリセットフォームを送信したとき、最近のWebサイトがどのように反応するかお気づきでしょうか?これまでのWebサイトのように「パスワードリセット用のリンクを送信しました」「指定されたメールアドレスは当社のデータベース内にありません」といったメッセージは表示されません。その代わり、「このメールアドレスが当社のデータベース内にある場合は、メールでリンクをお送りします」のようなメッセージが表示されます。要するに、ユーザー名の存在をはっきりと確認もしなければ否定もしないのです。これは、ユーザー名列挙攻撃対策としての措置です。
同じ理由から、入力したパスワードが間違っていることや、そのようなユーザー名が存在しないことを、ログインウィンドウで詳しく説明する必要もありません。ただ単に、入力されたログインIDとパスワードの組み合わせが見つからなかったと伝えればいいのです。利用者が受ける印象としては、確かに理想的ではありません。個人的には、登録に使ったメールアドレスがどれだったかは忘れたけれどもパスワードは確実に覚えている(またはその逆である)場合に、自分がどの情報の入力を間違えたのか分からないとイライラします。しかし、セキュリティは実質的に快適さを常に犠牲にするものですから、認証に関して多少セキュリティに偏るのは理にかなっています。
もちろん、CAPTCHAの使用やログイン試行回数の制限は必須です。その上で、Webアプリケーションの安全性を確保するために、第三者による監査を受けることをお勧めします。