<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>公開鍵暗号 on M1KE BL0G</title><link>https://www.m1ke.org/tags/%E5%85%AC%E9%96%8B%E9%8D%B5%E6%9A%97%E5%8F%B7/</link><description>Recent content in 公開鍵暗号 on M1KE BL0G</description><generator>Hugo -- gohugo.io</generator><language>ja-jp</language><copyright>mike</copyright><lastBuildDate>Mon, 19 Oct 2026 09:50:00 +0900</lastBuildDate><atom:link href="https://www.m1ke.org/tags/%E5%85%AC%E9%96%8B%E9%8D%B5%E6%9A%97%E5%8F%B7/index.xml" rel="self" type="application/rss+xml"/><item><title>パスキーの仕組み</title><link>https://www.m1ke.org/p/%E3%83%91%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF/</link><pubDate>Mon, 19 Oct 2026 09:50:00 +0900</pubDate><guid>https://www.m1ke.org/p/%E3%83%91%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF/</guid><description>&lt;img src="https://www.m1ke.org/p/%E3%83%91%E3%82%B9%E3%82%AD%E3%83%BC%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF/pk.webp" alt="Featured image of post パスキーの仕組み" /&gt;&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;最近パスキーで認証するシステムを実装した&lt;/li&gt;
&lt;li&gt;パスワードを使わない公開非公開鍵方式でCryptみたいに便利だった&lt;/li&gt;
&lt;li&gt;その仕組みを整理した&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="パスキーとは"&gt;パスキーとは&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;FIDO Allianceの定義によれば、パスキーとは「FIDO標準に基づく認証情報で、スマートフォンやPC、またはハードウェアセキュリティキーに保存できるもの」&lt;/li&gt;
&lt;li&gt;中身は公開鍵暗号の鍵ペア。パスワードのような「サーバーと共有する秘密の文字列」ではなく、デバイス側に秘密鍵を保持し、サーバー側には公開鍵だけを保存する方式&lt;/li&gt;
&lt;li&gt;ログイン時は、デバイスのロック解除と同じ操作（生体認証・PIN・パターンなど）で承認するだけで済む&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="公開鍵暗号を使った認証の仕組み"&gt;公開鍵暗号を使った認証の仕組み&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;WebAuthn（ブラウザが提供するAPI）の用語では、サービス側を「Relying Party（RP）」、ブラウザを「Client」、鍵ペアを生成・保管する側（スマートフォンやセキュリティキーなど）を「Authenticator」と呼ぶ&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="登録registration"&gt;登録（Registration）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ユーザーがアカウント登録・新しいパスキーの追加を行うと、ブラウザは&lt;code&gt;navigator.credentials.create()&lt;/code&gt;を呼び出す&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;191&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;241&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;rp&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acme.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ACME Corporation&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;252&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;72&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;214&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;jamiedoe&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Jamie Doe&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;pubKeyCredParams&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public-key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alg&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Authenticatorが、そのRPに紐づく公開鍵・秘密鍵のペアを新しく生成する&lt;/li&gt;
&lt;li&gt;秘密鍵はAuthenticator内に残り、外に出ることはない。公開鍵だけがRPに送られ、ユーザーアカウントに紐づけて保存される&lt;/li&gt;
&lt;li&gt;この際、Authenticatorが自分の正当性を証明する「Attestation（証明）」という情報も一緒に返されることがある&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="認証authentication"&gt;認証（Authentication）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ログイン時は、ブラウザが&lt;code&gt;navigator.credentials.get()&lt;/code&gt;を呼び出す&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;publicKey&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;139&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;181&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;87&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;203&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;rpId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acme.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;allowCredentials&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;public-key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;168&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;226&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;174&lt;/span&gt; &lt;span class="cm"&gt;/* … */&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;userVerification&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;RPがランダムな challenge（毎回変わる使い捨ての値）を発行する&lt;/li&gt;
&lt;li&gt;Authenticatorが、デバイスのロック解除などでユーザー本人であることを確認した上で、保存していた秘密鍵でそのchallengeに署名する&lt;/li&gt;
&lt;li&gt;RPは、登録時に保存しておいた公開鍵を使って、その署名を検証する。秘密鍵そのものはネットワーク上を一切流れない&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="なぜフィッシング耐性があるのか"&gt;なぜフィッシング耐性があるのか&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;署名の対象には、challengeだけでなく、RP ID（アクセス先のドメイン）も含まれる&lt;/li&gt;
&lt;li&gt;例えば正規サイトが&lt;code&gt;acme.com&lt;/code&gt;だとして、攻撃者が&lt;code&gt;acme-fake.com&lt;/code&gt;のようなフィッシングサイトを用意しても、Authenticatorはそのドメイン向けの署名を作ってくれない。署名がオリジン（ドメイン）に紐づいているため、別ドメインでは再利用できない&lt;/li&gt;
&lt;li&gt;パスワードのように「人間がどのサイトにいるか勘違いして入力してしまう」という失敗がそもそも起こり得ない設計になっている&lt;/li&gt;
&lt;li&gt;Yubicoのデータでは、パスキーによってフィッシング・認証情報窃取へのリスクが99.99%減少するとされている&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="discoverable-credentialresident-key"&gt;Discoverable Credential（Resident Key）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;通常のWebAuthn認証では、RPが&lt;code&gt;allowCredentials&lt;/code&gt;でcredential IDを指定する必要があるが、パスキーは「Discoverable Credential（かつてはResident Keyと呼ばれた）」という形式を使う&lt;/li&gt;
&lt;li&gt;これは、RP IDさえ分かれば、Authenticator側に保存された資格情報を自分で見つけ出し、署名を生成できる方式&lt;/li&gt;
&lt;li&gt;この「Client-side Discoverable Credential」のうち、複数デバイス間で同期されるものが、一般に「パスキー」と呼ばれている&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="webauthnfido2ctapの関係"&gt;WebAuthn・FIDO2・CTAPの関係&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;WebAuthnは、ブラウザが提供する、Webサイトから公開鍵認証を扱うためのJavaScript API（W3Cの標準）&lt;/li&gt;
&lt;li&gt;CTAP（Client to Authenticator Protocol）は、ブラウザ（Client）と、USBキーやスマートフォンなどの外部Authenticatorとの間の通信プロトコル&lt;/li&gt;
&lt;li&gt;WebAuthn + CTAPをあわせて「FIDO2」と呼ぶ。パスキーは、このFIDO2の標準をベースにした実装にあたる&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="デバイス間の同期"&gt;デバイス間の同期&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;パスキーの保存・同期方法には、大きく2種類ある&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;種類&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;同期パスキー（Synced passkeys）&lt;/td&gt;
&lt;td&gt;iCloudキーチェーンやGoogleパスワードマネージャーなどのクラウド経由で、同じアカウントの他のデバイスにも自動的に複製される&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;デバイス固定パスキー（Device-bound passkeys）&lt;/td&gt;
&lt;td&gt;特定の1台のデバイスやハードウェアセキュリティキーの中に留まり、クラウドには同期されない&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;自分のスマートフォンにパスキーがあり、PC側にはまだ登録していない場合でも、FIDOのCross-Device Authenticationという仕組みで、Bluetoothによる近接確認を行った上で、スマートフォン経由でPC側のログインを完了できる&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="まとめ"&gt;まとめ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;パスキーは、公開鍵暗号の鍵ペアをベースにした認証方式で、秘密鍵はデバイス（Authenticator）内に留まり、サーバー（RP）には公開鍵だけが保存される&lt;/li&gt;
&lt;li&gt;登録（&lt;code&gt;navigator.credentials.create()&lt;/code&gt;）でAuthenticatorが鍵ペアを生成して公開鍵をRPに渡し、認証（&lt;code&gt;navigator.credentials.get()&lt;/code&gt;）ではRPが発行したchallengeに秘密鍵で署名することで、本人確認が行われる&lt;/li&gt;
&lt;li&gt;署名がRP ID（ドメイン）に紐づいているため、フィッシングサイトでは署名が成立せず、パスワードと違って原理的にフィッシング耐性を持つ&lt;/li&gt;
&lt;li&gt;パスキーは、RP IDだけで資格情報を特定できるDiscoverable Credentialという形式をベースにしており、WebAuthn・CTAPをあわせたFIDO2標準の実装にあたる&lt;/li&gt;
&lt;li&gt;同期パスキー（クラウド経由で複数デバイスに複製）とデバイス固定パスキー（1台に留まる）の2種類があり、Bluetoothによる近接確認を使ったデバイス間認証の仕組みもある&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考文献"&gt;参考文献&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.w3.org/TR/webauthn-3/" target="_blank" rel="noopener"
&gt;Web Authentication: An API for accessing Public Key Credentials - Level 3 (W3C)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://fidoalliance.org/passkeys/" target="_blank" rel="noopener"
&gt;Passkeys - FIDO Alliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API" target="_blank" rel="noopener"
&gt;Web Authentication API - MDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>