はじめに
SMSやメールを使用したワンタイムパスワード(OTP)認証はユーザ側に事前準備がいらないため、導入のしやすさから多くの場面で使用されています。
しかし、OTP認証には明確な弱点があります。
それは、OTPを入力する先が正しいサイトかどうかの確認がユーザーに委ねられていることです。
そのため、一般的なOTP認証の実装では、ユーザーがフィッシングサイトにOTPを入力してしまうことを完全に防ぐことは、仕様上困難です。
そのような背景から、近年ではOTPを用いた2要素認証に代わり、パスキーを利用したフィッシング耐性のある認証の導入が進んでいます。
例えば、高いセキュリティが要求される証券業界では、フィッシングに耐性のある多要素認証を必須とすることがガイドラインで定められています。
フィッシングに耐性のある多要素認証4(例:パスキーによる認証、PKI(公開鍵基盤)をベースとした認証)の実装及び必須化(デフォルトとして設定)する
本記事では、実際にフィッシングサイトを用意し、攻撃者がOTPをどのようにバイパスできるかを示すことで、OTP認証がフィッシングに脆弱であることを実践的に確認してみます。
また、パスキー認証がフィッシングに高い耐性を持つことも確認します。
攻撃者がフィッシングサイトを使ってOTPをバイパスする様子を実践する
実際にOTPで2要素認証を実施しているサービス(以下、正規サイト)に対して、フィッシングによってOTPをバイパスしてみましょう。
フィッシングサイトを用意し、ユーザーをフィッシングサイト経由で正規サイトにログインさせ、その過程でセッションCookieを詐取します。
攻撃者は詐取したセッションCookieを使用して認証をバイパスすることができます。
用意した環境
フィッシングによってOTPをバイパスするための環境をローカルに用意しました。
本記事で紹介する攻撃手法および検証環境は、セキュリティ理解を目的とした検証用のローカル環境でのみ実施しています。
実在するサービスや第三者に対してこれらの手法を試さないでください。
構成要素
今回のシナリオに登場する構成要素の概要です。
- 正規サイト
- ユーザー向けに何らかのサービスを提供していて、ログイン機能を有しています。
- ユーザーを認証するために、ID/PW認証とOTP認証の2要素認証を行っています。
- ドメイン名:
idp.service.local
- フィッシングサイト
- 攻撃者が設置したフィッシング用のサイトです。
- 中間者として動作し、ユーザーからの要求と正規サイトからの応答を中継するとともに、認証情報を詐取します。
- ドメイン名:
evil.phishing.local
- 攻撃者
- フィッシングサイトを設置します。
- フィッシングサイトのURLをユーザーに送り付け、ユーザーにフィッシングサイト経由で正規サイトにログインさせることによって、セッションCookieの詐取を試みます。
- ユーザー
- 正規サイトを利用しているユーザーです。
- 攻撃者から送られてきたURLにアクセスして認証を行った結果、セッションCookieを攻撃者に詐取されてしまいます。
構成図
今回のシナリオは下記の構成で実施しています。
正規サイトは認証を提供しており、ユーザーに対して認証済みであることを示すCookieを発行します。
フィッシングサイトはユーザーと正規サイトの中間者として動作します。
フィッシングサイトはブラウザに信頼されるサーバ証明書を保有しています。
TLSを終端するので、ユーザーからの入力と正規サイトからの応答を記録できます。

正規サイトの認証フロー
正規サイトは以下の認証フローでユーザー認証を行っています。
認証に成功した場合にはセッションCookieを発行し、セッションCookieが有効な間は、ブラウザがCookieを提示してきた場合は認証済みとします。
攻撃のシナリオ
攻撃のシナリオは下記のようになっています。
念のために再度記載しますが、今回のシナリオに関与するすべての要素はローカル環境に自分で用意したものです。
1.攻撃者がユーザーにフィッシングサイトのURLを送りつける
攻撃者がフィッシングサイトのURLをユーザーにメール等で送りつけます。
今回は下記の偽URLをユーザーに踏ませる想定です。
偽URL:https://evil.phishing.local/auth/
正規URL:https://idp.service.local/auth/
これは明らかに怪しいURLですが、実際の攻撃者はより本物に見えるURLを、もっともらしい文面と一緒に送信してきます。
下記サイトでは実際のフィッシングの事例を確認できます。
https://www.antiphishing.jp/news/alert/openai_chatgpt_20251202.html
2.ユーザーがフィッシングサイトにアクセスする
攻撃者から送られてきた偽URLを正規サイトのものと思いこんだユーザーは、フィッシングサイトにアクセスしてしまいます。
フィッシングサイトはユーザーと正規サイトの間に入って通信を中継し、正規サービスからの応答をそのままユーザーに転送するので、フィッシングサイトと正規サイトの外見はほぼ同じです。
そのため、フィッシングサイトであることを外見から判別することは難しいです。
今回のシナリオでも、フィッシングサイトのログイン画面と正規サイトのログイン画面は全く同じで、URLのみが異なります。
怪しいサイトにはブラウザが警告を表示してくれると思われがちですが、
フィッシングサイトであっても、正規の認証局から発行されたサーバ証明書を利用しているケースが多くあります。
この場合、ブラウザの証明書検証は正しく機能しており、通信は暗号化されます。
しかし、「そのサイトが本物のサービスであるかどうか」までは保証するものではなく、ブラウザからの警告は期待できません。
フィッシングサイトのドメイン名(URL)は正規のものと異なっていますが、常にURLを気にする人は(世間一般でいうと)それほど多くはないのではないでしょうか。
3.ユーザーがフィッシングサイト経由で認証を成功させる
ユーザーはフィッシングサイト経由で正規サイトとやりとりをして、認証を行います。
ユーザーがフィッシングサイトにID/PWとOTPを入力してしまい、それをフィッシングサイトが正規サイトに転送します。
正規サイトとしては、正しい認証情報が送られてきたので認証成功となります。
人間は不注意です。
知識としてURLを確認しなければならないことは知っていても、心理的状態や体調によってはURLを確認せずに認証情報を入力してしまうこともあります。
認証情報を正しいサイトにしか提示できない仕組みがあれば、フィッシング被害に遭う確率は大きく下がるでしょう。
後述するパスキーはそのような仕組みになっています。
4.フィッシングサイトがセッションCookieを詐取する
正規サイトはユーザーが認証に成功すると、認証済みであることを示すセッションCookieを発行します。
ユーザーと正規サイトの中間者として動作しているフィッシングサイトはこのセッションCookieを詐取することができます。
ここで重要なのは、セッションCookieは「認証済みユーザーであること」を証明する情報だという点です。
攻撃者がこのCookieを入手すると、たとえパスワードやOTPを知らなくても、
認証済みユーザーになりすました状態で正規サイトにアクセスできてしまいます。
下記は、今回のシナリオで詐取したセッションCookieです。IDPCookieは正規サイトが認証済みユーザに発行するセッションCookieです。(ログが古いですが、検証時のものです)
[Thu Dec 18 18:08:46.469399 2025]
IDPCookie=AQIC5wM2LY4SfcwLa1LWYYh55sQqAL37TrtdQmj4abheRJw.*AAJTSQACMDEAAlNLABM3NTI1NzAyMzU1MTIzMjQwNzI0AAJTMQAA*\r\n
CookieにはDomain属性が付与されている場合もありますが、その場合にはフィッシングサイトが属性値を書き換えてユーザーに転送します。
CookieのDomain属性は、そのCookieを「どのドメインに送信するか」をブラウザに指示するための属性です。
Domain=example.com
→ example.comおよびwww.example.comやlogin.example.comなどのサブドメイン全体でCookieが送信されます。
5.攻撃者が詐取したCookieでログインする
攻撃者がセッションCookieをブラウザに配置して、正規サイトにアクセスします。
正規サイトにセッションCookieを提示することで、そのセッションCookieが有効な間はID/PW認証とOTP認証をバイパスすることができます。
下記画面のように、攻撃者は認証をバイパスして、セッションCookieを詐取されたユーザーとしてログインすることができます。
phishing_testはフィッシング被害にあってしまったユーザーのユーザー名です。
攻撃者はphishing_testユーザーの2段階認証用デバイスに攻撃者が所有するデバイスを登録するなどして、攻撃を継続しようとします。
サービスに対してフィッシングによる攻撃が成功しましたが、これは認証に使用しているソフトウェアの脆弱性に起因するものではありません。
サービス提供者がフィッシングに対して耐性の低い認証方式を選択していることに起因するものです。
パスキーを導入するとフィッシング耐性が高まる
ID/PW認証やOTP認証は、ユーザーが間違ったサイトにID/PWやOTPを入力しないことを前提としています。
そのため、不注意なユーザーがフィッシングサイトに認証情報を入力してしまうことが原因で、フィッシングが成立してしまいます。
パスキー認証を導入することで、上記の原因を取り除いてフィッシング耐性を高めることができます。
パスキーを使用した認証の概要
パスキーは、ユーザーの端末に安全に保存された秘密鍵と、サービス側に登録された公開鍵のペアを用いて認証を行う仕組みです。
ユーザーが秘密鍵によって生成する署名をサービス側に登録されている公開鍵で検証できるか確認するものとなります。
公開鍵で検証できるような署名を作成できるのは秘密鍵を持っている人だけなので、「所有」の認証となります。
なぜパスキー認証はフィッシング耐性が高いのか
認証情報の提示先が正しいドメインであることを、人ではなくブラウザが検証する仕様だからです。
ユーザーがフィッシングサイトevil.phishing.local経由で正規サイトidp.service.localの認証情報を提示しようとしても、
ブラウザは認証要求元のオリジンに基づいて使用可能なクレデンシャルを選択します。そのため、フィッシングサイト経由では正規サイト用のパスキーが使用されません。
ユーザー(WindowsやiPhoneといったユーザーが利用しているプラットフォーム)はフィッシングサイトのパスキーを持っていないので認証できません。
この仕組みによって、パスキー認証はフィッシングに対して強い耐性を持ちます。

パスキーを導入してみる
実際に正規サイトにパスキー認証を導入して、ユーザーが直接パスキー認証をする場合とユーザーがフィッシングサイト経由でパスキー認証をする場合を比較してみます。
ユーザーが正規サイトで直接パスキー認証する場合
正規サイトのドメインidp.service.localに対応したパスキーで認証が行われ、ログインに成功します。

ユーザーがフィッシングサイト経由でパスキー認証する場合
フィッシングサイト経由だと、フィッシングサイトのドメインevil.phishing.localに対応するパスキーで認証しようとします。
ユーザーはフィッシングサイトのドメインに対応するパスキーを持っていませんのでログインできません。
[余談] OTPを比較的安全に使用するための仕組みもあるが、不十分
パスキー認証を導入することで、OTP 認証と比べてフィッシング耐性が大きく向上することを示しました。
ブラウザやプラットフォームによっては、ユーザーがフィッシングサイトにOTPを入力してしまうことを抑制する仕組みがあります。
一例として、Safariは、SMSで受信した OTPをブラウザに自動入力する仕組みを持ちますが、Domain-bound SMS OTPという仕様により、SMSに含まれるOTPを、SMS内で指定されたドメインを開いている場合にしか自動入力候補として提示しないようになっています。
そのため、ユーザーがフィッシングサイトを開いている場合には、普段表示されるはずの OTP の自動入力候補が表示されません。
SMSで受信したOTPが自動入力されることに慣れているユーザーほど、この「いつもと違う挙動」に違和感を覚え、フィッシングサイトで認証しようとしていることに気づくきっかけになることが期待されます。
ただし、このような仕組みはあくまで UIレベルでの誤入力を防ぐための対策であり、かつクライアント側プラットフォームに依存するものです。
そのため、サービス側がフィッシング耐性の高い認証方式(パスキーなど)を提供すべきであるという点に変わりはありません。
まとめ
2要素認証としてOTPを使用しているサービスは、フィッシングに対して脆弱なことを実践的に確認しました。
これは、ID/PW認証やOTP認証では、認証情報を提示する先が正規のサイトかどうかの判断をユーザーに委ねていることが原因です。
もちろん、OTP認証はパスワード単体よりもはるかに安全であり、依然として有効な多要素認証の一形態です。
ただし、フィッシング耐性という観点では、パスキー認証が大きな優位性を持っています。
パスキー認証では、パスキー認証を要求しているドメインに対応するパスキーしか使用することができないのでフィッシングに対して高い耐性を実現することができます。
参考資料
「パスキーのすべて」
https://gihyo.jp/book/2025/978-4-297-14653-5
FIDO2 がフィッシング耐性がある認証 (MFA) と呼ばれる理由
https://qiita.com/narisho/items/200f757f16e51a0bef6a



