1
認証サービスへのWebAuthnの導入
GMOインターネット株式会社
次世代システム研究室
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
2
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
3
• リスト型攻撃
https://www.ipa.go.jp/files/000041743.png
4
https://www.fastretailing.com/jp/group/news/1905132000.html
5
• フィッシング
https://www.ipa.go.jp/files/000015220.gif
6
https://www.antiphishing.jp/report/images/report_monthly202008_1.png
7
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
8
• WebAuthnとは
Webブラウザで生体認証を実現できる技術
9
• IdPでの導入事例
https://about.yahoo.co.jp/pr/release/2021/02/08a/
10
https://s.yimg.jp/images/tecblog/2020-H2/ac_webauthn/01_yahoo.png
11
セキュリティ向上
• パスワードを送信しないことによる盗聴対策
• リスト型攻撃やフィッシングへの対策としても機能する
https://www.fujitsu.com/jp/solutions/business-technology/security/secure/event/fujitsu-forum/2019/S2-26.pdf
12
13
• 単体の仕組みで2要素認証を実現
• 認証器に保存された認証情報と生体認証の組み合わせ(所有要素と生体要素)
• 認証の3要素
• 知識要素
• パスワード、暗証番号等
• 所有要素
• SMS認証、IDカード等
• 生体要素
• 指紋認証、顔認証等
ユーザービリティ向上
• WebAuthnを用いたパスワードレス生体認証のユーザビリティ調査 Yahoo! JAPAN研究所
https://s.yimg.jp/images/tecblog/2020-H2/ac_webauthn/02_bonneau.png
14
ユーザビリティ
• ざっくりまとめ
15
利点/認証手順 生体認証 パスワード認証 SMS認証
ユーザーの記憶が不要 ○ × ○
ユーザーの動作の少なさ ○ △ ×
認証に失敗する頻度 △ △ △
紛失時の復旧 △ ○ △
導入しやすさ
△(ISP視点)
○(IdP視点)
○ △
セキュリティ ○ × ○
• パスワード認証との比較
https://s.yimg.jp/images/tecblog/2020-H2/ac_webauthn/03_authenticationtime.png
https://s.yimg.jp/images/tecblog/2020-H2/ac_webauthn/04_authenticationtime_table.png
16
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
17
FIDO2
• FIDO2とは
Webブラウザから認証器を扱う仕様(WebAuthn)と認証器との連携プロトコル(CTAP)の総称
https://medium.com/webauthnworks/introduction-to-webauthn-api-5fd1fb46c285
18
• FIDO(Fast IDentity Online)
生体認証等を利用した新しいオンライン認証技術の標準化団体
• FIDO UAF
FIDOに対応するデバイスを利用してパスワードを使わないで認証を行う仕組み
• CTAP
USB、NFC、BLEを使った認証器との通信プロトコル
• CTAP1
FIDOに対応するデバイスで2段階認証するための仕様
• CTAP2
より広い利用シーンに適応できる仕様が追加されたバージョン
CTAP1への下位互換性あり
19
• WebAuthnとは
W3Cで標準化されている、認証情報を扱うためのJavaScriptのAPI
https://medium.com/webauthnworks/introduction-to-webauthn-api-5fd1fb46c285
20
用語
• Public Key Credential Source
認証器が認証アサーション(本人主張)を生成するために使用する認証情報のソース、秘密鍵を含む
• Server-Side Public Key Credential Source
サーバー側で認証アサーションを検証するために使用する認証情報のソース、公開鍵を含む
• Credential ID
Public Key Credential Sourceを識別するID、サーバーとWebブラウザはこのID経由でやり取りする
• Relying Party、RP ID
ISPやIdPを指すもの、RP IDはホストのドメイン
• User Handle
ユーザー識別子
• challenge
署名用の文字列、認証器の秘密鍵で暗号化してサーバー側に送られた公開鍵で復号化して突合して認証を通す
21
• 登録フロー
https://www.gmo-jisedai.com/wp-content/uploads/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2018-10-10-16.22.50.png
1. ユーザー(エージェント)がチャレンジを取得
2. 秘密鍵生成
3. チャレンジを暗号化してサーバーに送信
4. 暗号化されたチャレンジを公開鍵で復号化してチャレンジの値を確認
22
• 認証フロー
https://www.gmo-jisedai.com/wp-content/uploads/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88-2018-10-10-16.25.02.png
1. ユーザー(エージェント)がチャレンジと秘密鍵のIDを取得
2. 秘密鍵取得
3. チャレンジを暗号化してサーバーに送信
4. 暗号化されたチャレンジを公開鍵で復号化してチャレンジの値を確認
23
WebAuthn
• WebAuthnの全体像
24
Public Key
Credential
Source
type
id
privateKey
rpId
userHandle
Server-Side
Public Key
Credential
Source
WebAuthn API
rpId、userHandle、challenge
rpId、userHandle、challenge、publicKey
userHandle
credentialId
publicKey
…
Credential
• Public Key Credential Source
25
type: public-key
id: AanNf7FX0UTi6GuTdpXBs44AgdC-
lHlxUbN4cF2qM2tou7VbVPh0rXhalu8
privateKey: …
rpId: stg.gmo.jp
userHandle: John Doe
Public Key Credential Source
id:…
id:…
id: AanNf7…
challenge: plain
id: AanNf7…
challenge: plain
challenge: encrypted challenge: encrypted
• ドメインがスコープされる仕組み
アクセスしたドメインとRP IDが異なる場合は参照しない(サブドメインは可能)
26
Public Key Credential Source
stg.gmo.jp
type: public-key
id: AanNf7FX0UTi6GuTdpXBs44AgdC-
lHlxUbN4cF2qM2tou7VbVPh0rXhalu8
privateKey: …
rpId: stg.gmo.jp
userHandle: John Doe
sub.stg.gmo.jp
stg.example.com
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
27
• 導入対象の認証サービスのシステム概要
• 認証サービスはIdPで、様々なサービスでスマートフォンとPCから利用される
• WebAuthn導入後(スマートフォンのみ)のイメージ
28
• 認証以外のユーザーシナリオ
• 認証器の紛失・盗難
• 複数認証器を登録できる
• 紛失・盗難時は所持している認証器でログインして認証器設定削除
• 単一ユーザーでの複数認証器の利用
• 複数認証器を登録できる
29
• 用意するもの
ローカル環境でも開発可能
ドメイン名はローカル環境のhostsへの記載で問題なし
SSL証明書は自己証明書で問題なし
WebAuthn対応ブラウザ
Yubikey(あると便利)
30
• WebAuthn API
• Public Key Credential Sourceの生成
navigator.credentials.create({'publicKey': options })
• Public Key Credential Sourceの取得
navigator.credentials.get({'publicKey': options })
31
• navigator.credentials.create
• optionsの仕様
32
rp:
{ name: RP Server, id: stg.gmo.jp }
pubKeyCredParams:
{ type: public-key, alg: -7 } // ES256
challenge: HGHnlG83gWAVKKOEbPvtONAYjtu80nlqrL4CvPOkpXs
attestation: none
user:
{ name: john.doe, id: am9obi5kb2U=, displayName: John Doe }
authenticatorSelection:
{ requireResidentKey: false, userVerification: preferred }
excludeCredentials:
[]
timeout: 60000
• navigator.credentials.createの呼び出し
33
const options = JSON.parse(‘{"rp":{"name":"RP Server”,id:…}');
navigator.credentials.create({ 'publicKey': options })
.then(function(data) {
const publicKeyCredential = {
id: data.id,
type: data.type,
rawId: data.rawId,
response: {
clientDataJSON: data.response.clientDataJSON,
attestationObject: data.response.attestationObject
}
};
// サーバーへの送信処理
})
.catch(function(error){
// エラー処理
});
• 出力の値
34
id: Ypnys30jfV..
type: public-key
rawId: Ypnys30jfV..
response:
{
clientDataJSON: eyJjaGFsbG..,
attestationObject: o2NmbXRkbm..
}
• 登録済み端末の判別
35
excludeCredentials:
[{
type: public-key,
id: Ypnys30jfV...,
transports: [internal, usb]
}]
• navigator.credentials.get
• optionsの仕様
36
challenge: THRb7S2ZhDdchfBydOGixw1AL2ikXxB2vG0m91eAKdU
rpId: stg.gmo.jp
userVerification: preferred
allowCredentials:
[{
type: public-key, id: Ypnys30jf.., transports: [internal, usb]
}]
timeout: 60000
• navigator.credentials.getの呼び出し
37
const publicKey = JSON.parse(‘{“challenge”:”THRb7S2Zh..”,”rpId”:..}’);
navigator.credentials.get({ 'publicKey': options })
.then(function(data){
const publicKeyCredential = {
id: data.id,
type: data.type,
rawId: data.rawId,
response: {
authenticatorData: data.response.authenticatorData,
clientDataJSON: data.response.clientDataJSON,
signature: data.response.signature
}
};
// サーバーへの送信処理
})
.catch(function(error){
// エラー処理
});
• 出力の値
38
id: Ypnys30jfV..
type: public-key
rawId: Ypnys30jfV..,
response:
{
authenticatorData: dRgAXdaM8..,
clientDataJSON: eyJ0eXBlI..,
signature: MEQCIGSph..
}
• 生体認証の設定
• createのoptions
• getのoptions
39
authenticatorSelection:
{
userVerification: required,
authenticatorAttachment: platform
}
allowCredentials:
[{
transports: [internal]
}]
• FIDO2の補足説明
• FIDO2 ≠ スマートフォンでの生体認証の仕様
• パスワードとセキュリティキーを組み合わせた2要素認証(知識認証と所有認証)
userVerification = preferredで所有認証が利用可能
https://ftsafe.co.jp/wp/wp-content/themes/ftsafePCSP2016/img/add_03.jpg
40
• JavaScript実装の補足説明
• 型変換とエンコードが必要
41
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), function(c){return c.charCodeAt(0);});
clientDataJSON: arrayToBase64String(new Uint8Array(credential.response.clientDataJSON)),
attestationObject: arrayToBase64String(new Uint8Array(data.response.attestationObject)),
authenticatorData: arrayToBase64String(new Uint8Array(credential.response.authenticatorData)),
signature: arrayToBase64String(new Uint8Array(credential.response.signature))
function arrayToBase64String(a) {
return btoa(String.fromCharCode(...a));
}
function base64url2base64(input) {
input = input.replace(/=/g, "").replace(/-/g, '+').replace(/_/g, '/');
const pad = input.length % 4;
if (pad) {
input += new Array(5-pad).join('=');
}
return input;
}
• PHPライブラリの紹介
• https://github.com/web-auth/webauthn-lib
• 認証フローに必要な実装あり
• 開発ドキュメントあり
• 一通りのAttestation Statement Formatsに対応
42
• 登録時(navigator.credentials.createのレスポンス)の処理
• navigator.credentials.createからのレスポンスの内容の検証
• Server-Side Public Key Credential Sourceの保存
43
id: Ypnys30jfV..
type: public-key
rawId: Ypnys30jfV..
response:
{
clientDataJSON: eyJjaGFsbG..,
attestationObject: o2NmbXRkbm..
}
$credential_response = '{"id":"Ypnys30jfV..","type":..}';
$creation_options = loadSessionForPublicKeyCredentialCreation(); // challengeの値含む
$credential_source = loadAndCheckAttestationResponse($credential_response, $creation_options);
registerPublicKeyCredential($public_key_credential_source);
credential_response
• navigator.credentials.createのレスポンスの仕様と検証内容
44
response: { clientDataJSON: eyJjaGFsbG.., attestationObject: o2NmbXRkbm.. }
clientDataJSON:
{ type: webauthn.create, challenge: VBaL8urJ1R.., origin: https://stg.gmo.jp },
attestationObject:
fmt: none
attStmt: { }
authData:
rpIdHash: 7518005dd6..
flags:
{ UP: true, UV: false, AT: true, ED: false }
signCount: 1
attestedCredentialData:
aaguid: 00000000-0000-0000-0000-000000000000
credentialId: HZblViw33..
credentialPublicKey: pQECAyYgA..
変換
// UP = User Presence
// UV = User Verification
検証
保存
45
https://www.w3.org/TR/webauthn/images/fido-attestation-structures.svg
• リポジトリの設計
• 認証で利用するデータをカラムとして定義する
46
USER_CREDENTAIL_SOURCE
USER_HANDLE VARCHAR
CREDENTIAL_ID VARCHAR
CREDENTIAL_PUBLIC_KEY VARCHAR
…
• 認証時(navigator.credentials.getのレスポンス)の処理
• navigator.credentials.getからのレスポンスの内容の検証
47
id: Ypnys30jfV..
type: public-key
rawId: Ypnys30jfV..
response:
{
authenticatorData: dRgAXdaM8..,
clientDataJSON: eyJ0eXBlI..,
signature: MEQCIGSph..
}
$credential_response = '{"id":"Ypnys30jfV..","type":..}';
$request_options = loadSessionForPublicKeyCredentialRequest(); // challengeの値含む
$credential_source = loadAndCheckAssertionResponse($credential_response, $request_options, $user_entity);
doLogin($public_key_credential_source);
credential_response
• navigator.credentials.getのレスポンスの仕様と検証内容
48
response: { authenticatorData: dRgA.., clientDataJSON: eyJ0.., signature: MEQC.. }
authenticatorData:
rpIdHash: 7518005dd6..
flags:
{ UP: true, UV: false, AT: true, ED: false }
signCount: 1
attestedCredentialData:
aaguid: 00000000-0000-0000-0000-000000000000
credentialId: HZblViw33..
credentialPublicKey: pQECAyYgA..
clientDataJSON:
{ type: webauthn.get, challenge: qlo1KgQeoi.., origin: https://stg.gmo.jp },
signature: MEQC..
変換
// AttestationObjectのAuthDataと同じ型
検証
// AttestationObjectのclientDataJSONと同じ型
// 送信されたデータが改変されていないことを検証
• セキュリティ上の注意点
• challengeの生成
• RP Serverでランダムな値を生成すること
• 認証器が近くにあること
• USBやBLEを使う
他にも注意点あり
詳細はW3Cの仕様のセクション13と14を参照
49
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
50
• 計算量的安全性による暗号化の潜在的な脆弱性
分解に使った計算資源は1700コア・年、PCクラスターなど300台程度で約3年
公開鍵暗号で広く利用されているRSA暗号は計算力で解読可能
https://xtech.nikkei.com/it/article/NEWS/20100108/343056/
51
• 認証器の脆弱性
• FIDO2対応のセキュリティキーの脆弱性
• https://gigazine.net/news/20210108-google-titan-side-channel-attack/
52
• 悪意のある認証器
予めフィッシングサイト用のPublic Key Credential Sourceを登録
53
Public Key Credential Source
stg.gmo.jp
rpId: stg.gmo.jp
… sub.stg.gmo.jp
stg.example.com
rpId: stg.example.com
…
※実際に可能かは未検証
Attestationを利用した脆弱性対策
• Attestationとは
• RP Serverで使う公開鍵が正当な認証器から生成されたことを保証する仕組み
https://storage.googleapis.com/prd-hatena-engineering-asset/20190528114902.png
54
• attestation=noneの仕様
navigator.credentials.createで取得されるattestationObject
55
attestationObject:
fmt: none
attStmt: { }
authData:
attestedCredentialData:
aaguid: 00000000-0000-0000-0000-000000000000
credentialId: HZblViw33..
credentialPublicKey: pQECAyYgA..
• attestation=directの仕様
navigator.credentials.createで取得されるattestationObject
公開鍵の署名検証のデータが取得できる
56
attestationObject:
fmt: packed
attStmt: { alg: -7, sig: 304602210.., x5c:.. }
authData:
attestedCredentialData:
aaguid: 2fc0579f-8113-47ea-b116-bb5a8db9202a
credentialId: HZblViw33..
credentialPublicKey: pQECAyYgA..
• Attestation Statement Formatsの仕様
• 認証器の種類によっていくつかのフォーマットが存在
• Packed Attestation Statement Format
• TPM Attestation Statement Format
• Android Key Attestation Statement Format
• Android SafetyNet Attestation Statement Format
• FIDO U2F Attestation Statement Format
• None Attestation Statement Format
• Apple Anonymous Attestation Statement Format
57
• FIDO Metadata Service
• 認証器に関する脆弱性情報を提供するサービス
• 認証器の認証ステータスや脆弱性情報(toc.jwt)が取得できる
https://mds2.fidoalliance.org/tokens/
58
• toc.jwtの内容
59
{
"url": "https://mds2.fidoalliance.org/metadata/2fc0579f-8113-47ea-b116-bb5a8db9202a",
"timeOfLastStatusChange": "2020-05-12",
"aaguid": "2fc0579f-8113-47ea-b116-bb5a8db9202a",
"hash": "KPTWOX2ipTh03mE_GmtXLd-GZ691Riu8fAQCL2QPE9Q",
"statusReports": [
{
"status": "FIDO_CERTIFIED_L1",
"certificateNumber": "FIDO20020190826002",
"certificate": "",
"certificationDescriptor": "YubiKey 5 NFC Series",
"url": "",
"certificationRequirementsVersion": "1.3",
"certificationPolicyVersion": "1.1.1",
"effectiveDate": "2020-05-12"
}
]
},
アジェンダ
• WebAuthnを導入する背景
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
60
• 認証器の紛失や盗難
• 認証器の紛失や盗難によりログインが出来なくなる可能性
• 他の認証器でログインする
• 事前に他の認証器の登録が必要
• 手元にない認証器の登録は削除する
• ユーザーサポート経由で本人確認の上アカウントを復帰
• 事前に本人確認用の情報の登録が必要
• 手続き中はアカウント停止
61
• ブラウザキャッシュの削除
• ブラウザキャッシュの削除でログインが出来なくなる可能性
• SMS認証やOTP等と連携して別のログイン手段を提供する
• 生体認証が利用出来ない端末での利用
• 古いスマートフォンやPC等でログインする可能性
• SMS認証やOTP等と連携して別のログイン手段を提供する
• 2要素認証を実現するにはパスワード認証相当のものが必要
62
• パスワードレスを実現するには
• ユーザー視点でのパスワードレスの実現
• 複数認証器への対応
• SMS認証やOTP等と連携した別のログイン手段の提供
• パスワード認証のオプション化
• サービス提供者視点でのパスワードレスの実現
• 生体認証対応の認証器の更なる普及が必要
63
アジェンダ
• WebAuthnの概要
• WebAuthnの仕様
• 実装
• WebAuthnでの脆弱性対策
• パスワードレス認証の実現に向けて
• まとめ
64
まとめ
• FIDO2
https://fidoalliance.org/fido2-graphic-v2-2/?lang=ja
• WebAuthn API
• navigator.credentials.create({'publicKey': options })
• navigator.credentials.get({'publicKey': options })
65
• WebAuthnを導入することによるメリット
• 認証のセキュリティとユーザビリティの向上
• 認証をユーザー責任の世界からセキュリティコントロールの世界へ
• IdPでWebAuthnを導入して付加価値向上
• WebAuthn導入の注意点
• 様々な利用シーンに対応するためにSMS認証やOTP等との連携
• WebAuthnとしてのセキュリティ対策
• WebAuthnの脆弱性も視野に入れた開発運用
66

認証サービスへのWebAuthnの導入