*本記事は STORES Advent Calendar 2023 2日目の記事です
こんにちは。セキュリティ本部のsohです。
「パスキー(Passkeys)」が具体的に何を指しているのか、パスワードに比べて何がセキュアなのかが個人的に曖昧だったため、FIDOのサイトを見てみると以下のような文章が目に付きました。
Why passkeys? Passwords are a problem.
「なぜパスキーを利用するのか? - パスワードが問題だからです」
なかなか挑戦的な記述だと感じるかもしれません。実際パスキーは他の認証要素と比較してどんな点が優れているのでしょうか。
今回は「パスキー」の利点について調べてみます。
- パスキーを体験してみる
- そもそも認証って?
- パスワードの問題点とは
- 他の認証要素の問題点とは
- パスキーは何を解決するのか
- おわりに
- おまけ : STORES Advent Calendar 2023の宣伝
パスキーを体験してみる
認証の仕組みやパスキーの技術仕様について確認する前に、自身のデバイスで実際に試してみましょう。
FIDO公式サイトではいくつかのデモサイトが紹介されています。是非試してみてください。
また、以下の動画では、パスキーがどのように動作するかを示しています。
実際に試してみるとわかりますが、パスキーのユーザー体験はなめらかです。
また、触ってみるとサイト固有の「パスワード」のようなものを利用しないことにも気づくと思います。
そもそも認証って?
まず、「認証(Authentication)」の定義について確認しましょう。
「認証」とは本人であること確認することを指します。よく、Authnと略して記載することがあります。例えば、窓口で免許証など何らかの本人確認ができるものを提示する場合がありますが、それも広義の認証です。
認証に使用される要素は3つに大別されます。
- 知識要素
- 所有要素
- 生体要素
知識要素は、あなたが「知っていること(Something you know / SYK)」です。 たとえば、パスワードや好きなお店などが挙げられます。
所有要素はあなたが「所有しているもの(Something you have / SYH)」です。 たとえば、スマートフォンやセキュリティキー、ハードウェアトークンなどが挙げられます。
生体要素はあなたが「(主に生得的に)持っているもの(Something you are / SYA)」です。 たとえば、指紋、顔、虹彩など、あなたを固有の存在である「あなた」として認識できる何らかの要素が挙げられます。
認証では、これらの要素を1つまたはそれ以上使用します。 その要素は同じカテゴリの要素である場合もありますし、他の要素との組み合わせである場合もあります。
例えば、多くのログイン処理ではパスワードという「知識要素」のみで認証を行っていましたが、近年では、パスワードという「知識要素」に加え、他の要素を組み合わせた認証、すなわち「多要素認証(MFA)」を行うことが推奨されています。
MFAにおける追加要素は、SMS OTPやTOTPによる「所有要素」であったり、指紋や顔貌による「生体認証」であったりします。
パスワードの問題点とは
先述のMFAは、複数の認証要素(方法)を組み合わせることで「本人であること」の確認をより確実な形式で行おう、というものですが、各要素には構造上の欠陥(仕様)が存在します。
例えばパスワードの場合だと、ユーザーまたはサービス提供側がセキュアな(エントロピーの高い)パスワードを設定または許容しないことで、現実的な時間で不正にログインされてしまうことが考えられます。また、十分なエントロピーを確保していたとしても、あるサービスで認証情報が漏えいしてしまった場合や、ユーザーがフィッシング詐欺に遭ってしまった場合、その要素は無意味なものとなってしまう可能性があります。
このようにパスワードは覚えにくく取り扱いが難しい、さまざまな事象に左右されやすい要素であり、これらが問題点である、とされています。
また、ここでの問題点は、パスワード管理・生成がユーザーに委ねられているところにあります。
セキュリティエンジニアとしてはパスワードマネージャーの使用を強く推奨しますが、実際のところ、パスワードの漏えいを経験したことがないユーザーに対してパスワードマネージャーを利用する金銭的・心理的コストを上回るだけのメリットを提示することが難しいと感じています。
(ある種の正常性バイアスのようなものを超えるほどの説得を行うことは困難ですし、筆者自身、パスワードマネージャーを導入したきっかけは学生時代のクレジットカード不正利用被害でした...)
他の認証要素の問題点とは
OTPの問題点
一見堅牢に見えるOTP(ワンタイムパスワード)に対する攻撃として、Adversary-in-the-Middleが存在します。
この攻撃はフィッシングの一種で、フィッシングサイトがプロキシ/リバースプロキシとして動作します。
そのため、MFAとしてOTPが設定されていたとしても、攻撃者によってセッションが窃取されてしまいます。
(なお、この攻撃はOTPによるMFAだけではなく、アプリを利用したMFAに対しても有効な点には注意が必要です)
また、さまざまなサービスで導入されているSMS経由でのOTPですが、SMSは平文で送信されるため、中間者攻撃に脆弱とされています。
SIMスワップなど、電話番号自体を奪う攻撃も存在するため、認証要素の第一選択として用いることは非推奨とされることが多いです。
セキュリティキーの問題点
パスキーと同じFIDOベースの認証器として、真っ先に思いつくのはセキュリティキーです。
一般的なセキュリティキーはUSBやNFCでデバイスと接続し、後述のWebAuthnを利用して認証を行います。
ベースとしている技術はパスキーと同じなのですが、セキュリティキーの利用にはいくつかのハードルが存在します。
- ハードウェアデバイスとしてのセキュリティキーが必要なこと
- 紛失時にログインが行えなくなってしまうこと
まず、ハードウェアデバイスとしてのセキュリティキーを新規で購入し、それを常日頃から持ち運ぶ、というのは一般的なユーザーにとって現実的な方法ではないでしょう。
また、暗号鍵がセキュリティキー内部に保存されているため、故障時や紛失時にアカウントにログインできなくなってしまう、という自体が起こり得ます。この問題の軽減策として複数のセキュリティキーを購入することが考えられますが、これもユーザーにとっては金銭的負担が大きいです。
このようにハードウェアトークンはセキュリティ的に堅牢であるものの、一般に広がりづらい性質があるかと思います。
(筆者も一時期セキュリティキーを使用していましたが、対応サービスが少ないことや常日頃から持ち運ばなければいけないことが負担となり、使用を中止したことがあります)
パスキーは何を解決するのか
では、パスキーは何を解決してくれるのでしょうか。
まず公式サイトで紹介している、パスキーの定義について確認してみましょう。
Passkeys
/ˈpasˌkēs/
noun
Based on FIDO standards, passkeys are a replacement for passwords that provide faster, easier, and more secure sign-ins to websites and apps across a user’s devices. Unlike passwords, passkeys are always strong and phishing-resistant.
Passkeys simplify account registration for apps and websites, are easy to use, work across most of a user’s devices, and even work on other devices within physical proximity.
「パスキーはパスワードの置き換えであり、FIDO標準に基づいた形で、デバイスに跨るWebサイトまたはアプリとのサインインをより高速で容易かつセキュアに提供する。またパスワードと違って、パスキーは非常に堅牢でありフィッシング耐性もある。パスキーはアカウント登録をシンプルにするとともに、非常に使いやすく、殆どのユーザーのデバイスで動作し、物理的に近くにあるデバイス間でも動作する」
上記のとおり、パスキーはパスワードのより良い代替として設計されています。
認証フローの中で、PINまたは生体認証によって、認証器をアンロックする人物が端末の所有者であることをチェックします。すなわち、この時点で
- 所有要素(スマートフォンなどの認証器)
- 以下の何れか1つ
- 生体要素(指紋や顔貌)
- 知識要素(PINコード)
の2要素の組み合わせで認証を行うことになります。1
また、認証フローの中でオリジン(スキーム+ドメイン+ポート番号)の検証を行うため、フィッシングへの耐性も備えています。
くわえて、登録を行うWebサイトなどによって許可されている場合にはクロスプラットフォーム(外部認証器利用)での認証が可能です。たとえば、PC上でユーザー登録またはログインを行う際に、スマートフォンを認証器として使用することができます。(なお、iOS/Androidともに、「パスキー」をクラウド上にバックアップすることが可能です)
このように、パスキーを利用することで、セキュリティキーを紛失する可能性やパスワードのエントロピーについて意識することなく、セキュアな認証を行うことが可能です。
そもそもFIDOってなに?
FIDOとは、標準規格策定団体である「FIDO Alliance」が策定したオンライン認証規格です。
現行のFIDO2は以下のコンポーネントにより構成されています。
- WebAuthn
- CTAP
これらについて、簡略化したうえで解説します。
WebAuthnとは
WebAuthnとはブラウザーが公開鍵にアクセスするための標準規格(ブラウザAPI)です。
正式名称ではWeb Authentication APIと呼ばれ、パスワードの代替として公開鍵暗号を利用した認証を行うことが特徴です。
登録フロー
以下に登録フローを示します(いくつかのパラメーターはOptionalですが、あくまで例として記載しています)
サーバーからチャレンジ、ユーザー情報、Relying Party情報などをブラウザーに送信する
const publicKey = { challenge: Uint8Array(), // challenge: リプレイ攻撃対策のためのランダムな値。十分なエントロピーを確保するため、16バイト以上である必要がある rp: { id: "example.com", name: "EXAMPLE Corporation" }, // rp: Relying Partyの情報。ドメインのサブセットである必要があり、そうでない場合は登録に失敗する user: { // 登録するユーザーの情報 id: Uint8Array(), name: "John Doe", displayName: "John Doe" }, pubKeyCredParams: [ // pubKeyCredParams: 受け入れ可能な公開鍵の種類 { type: "public-key", alg: -7 // -8 (Ed25519) / -7 (ES256) / -257 (RS256) } ], authenticatorSelection: { authenticatorAttachment: "platform", // authenticatorAttachment: クロスプラットフォームかプラットフォーム固有かを示す }, timeout: 60000, // timeout: タイムアウト時間 attestation: "direct" // attestation: Attastationをどのように受け取るか } const attestation = await navigator.credentials.create({ publicKey })
ブラウザーから認証器に対して、
authenticatorMakeCredential()
を呼び出し、鍵ペアの作成を開始するここでは、ブラウザーにより、オリジンやチャレンジなどが
clientDataJSON
として、SHA-256ハッシュ値とともに渡されます認証器が鍵ペアなどを作成する
ここで認証器はデバイスの正当な所有者であることを確認するために、指紋やPINによる認証を行います
認証器からブラウザーに公開鍵などを含むアテステーションを返却する
3.で生成した公開鍵や認証IDなどが、
attestationObject
としてブラウザーに返却されますブラウザーからサーバーへ公開鍵などを送信する
PublicKeyCredential { rawId: ArrayBuffer(32), // rawId: 資格情報のID response: AuthenticatorAttestationResponse, authenticatorAttachment: 'platform', id: 'xxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_xxxx', type: 'public-key' }
サーバーが登録を完了する
ここでサーバーは5.の値の検証を行い、問題なければ登録を行います。たとえば、5.の
response
に含まれるclientDataJSON
は以下のような形式になっており、各値が想定されたものであるかを検証します{ "type": "webauthn.create", "challenge": "dT3857_xT_xTSNYHWRp1Pfznv_FP_FNI1gdZGg", "origin": "https://example.com:8443", "crossOrigin": false }
具体的な検証方法については、7.1. Registering a New Credential | Web Authentication: An API for accessing Public Key Credentials Level 3を確認してください
ログインフロー
ログインの際は以下のようなフローとなります。
サーバーからチャレンジ、IDなどを送信します
なお、ここで送信するIDは、登録フローの5.で返却された
rawId
となりますconst publicKey = { challenge: Uint8Array(), allowCredentials: [{ type: "public-key", id: rawId, // id: 登録フローの5.で返却されたrawId }], userVerification: "required", } const assertion = await navigator.credentials.get({ publicKey })
ブラウザーから認証器に対して、
authenticatorGetCredential()
を呼び出すここでは、ブラウザーにより、オリジンやチャレンジなどが
clientDataJSON
として、SHA-256ハッシュ値とともに渡されます認証器がアサーションを作成する
認証器はIDなどが正しいことを検証し、ユーザーの指紋やPINによる認証を行います。同意が取れたあと、登録時に生成された秘密鍵を用いて
clientDataHash
とauthenticatorData
に署名を行います- ブラウザーからサーバーへ各種情報を送信する
- サーバーが認証を完了する
ここでサーバーは5.の値の検証を行い、問題なければ認証を行います。 検証方法については、例えば3.の署名が正しいものであるか検証したり、チャレンジが正しいものであるかを検証したりします
CTAPとは
CTAPとは、Client to Authenticator Protocolの略であり、アプリケーションまたはOSがNFCやUSBなどを介して認証器と接続するためのプロトコルです。
例えば、スマートフォンを認証器として使用する場合、OSはCTAPを利用してスマートフォンと接続し一連の認証を行います。
パスキーの認証強度について
当然ですが、パスキーの認証強度は認証器の認証強度に依存する部分が非常に大きいです。
例えば、スマートフォンを認証器として利用していた場合、以下のようなパターンではパスキーが認証要素としての意味をなさなくなります。
- スマートフォンのPINコードが漏えいした
- スマートフォンの生体認証が突破された
- 端末アンロック後に生体認証が追加された
- 身動きが取れない状態で不正にロック解除された
- スマートフォン自体に何らかの脆弱性が存在し、攻撃者が任意のコードを実行できる
そのため、上記のようなリスクを避けるためには、ユーザーとしての防衛策として、認証要素を追加する、などが考えられます。
ただし、この場合でも、その認証要素が同一端末上で操作できるものである場合や何らかの脆弱性が存在する場合、パスキー同様攻撃者に突破される可能性が存在することに留意が必要です。
また、パスキー(秘密鍵)をクラウド上に保存しアカウント単位で共有している場合、利用している端末のうち何れかの認証が突破された場合にもアカウント侵害のリスクが発生します。
おわりに
今回はパスキーについて調べてみました。
- パスキーはパスワードに変わる認証要素
- 所有要素 +(知識要素 or 生体要素)
- フィッシング耐性を備える
- パスキーでも当然セキュリティ上の懸念は生じうる
- とはいえ、ユーザーにとって他の認証要素より扱いやすい
当然セキュリティは重要なのですが、複雑で扱いにくいものは一般に普及しません。
その意味において、パスキーはセキュリティ的に優れていながら一般ユーザーにも扱いやすい、優れた認証方法であると感じました。
(本記事の内容について技術的に誤っている点等ございましたら、Twitter等でお気軽にメンションいただけますと幸いです)
おまけ : STORES Advent Calendar 2023の宣伝
本記事は STORES Advent Calendar 2023 2日目の記事でした!
(前回の 初めて子ども向けのノベルティをデザインした話 by ちゅうかんさん もかわいいので是非御覧ください!)
次回は katsumata_ryo さんです。
- なおここではローカル認証について言及しているものであり、パスキーの利用によって生体情報やPINコードなどのデータがWebサイトに送信されることはありません↩