Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

FIDO認証によるパスワードレスログイン実装入門

5,698 views

Published on

HTML5 Conference2018で発表した内容です。 #html5j #html5j_a

Published in: Technology

FIDO認証によるパスワードレスログイン実装入門

  1. 1. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. FIDO認証による パスワードレスログイン実装入門 HTML5 Conference 2018 ヤフー株式会社 2018/11/25 合路 健人 @kg0r0
  2. 2. アジェンダ Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 2 1. 自己紹介 2. パスワード認証の課題 3. FIDOとは 4. FIDOの技術仕様 5. デモ 6. Web Authenticationフロー 7. まとめ
  3. 3. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 社内における認証をよりセキュアで使いやすくする取り組み 興味のある方は是非一緒にどうですか?? 新卒入社2年目 システム統括本部 プラットフォーム開発本部 アイデンティティー&アクセスマネジメント部 自己紹介 合路 健人
  4. 4. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 4 パスワード認証の課題
  5. 5. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 5 パスワード認証の課題(利便性) こんなことはありませんか  認証機会の増加  サービスごとに異なるパスワードを登録  複雑なパスワードの入力操作が不便
  6. 6. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 6 パスワード認証の課題(安全性) Client Server username + password DB DB LeakPhishing Password List Attack Dictionary Attack
  7. 7. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 7 FIDOとは
  8. 8. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 8 FIDO(Fast IDentity Online) パスワードへの依存度を減らし、利便性と安全性を向上する Poor Easy WeakStrong USABILITY SECURITY USABILITYSECURITY https://www.slideshare.net/FIDOAlliance/fido-83445442https://www.slideshare.net/FIDOAlliance/introduction-to-fido-alliance-66730790
  9. 9. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 9 FIDO認証モデル AuthenticatorUser verification FIDO Authentication challenge gesture signature privatekey publickey  公開鍵暗号方式による認証  オンラインサービスへの登録時に鍵ペアを生成して登録 client RP
  10. 10. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 10 用語説明  RP(Relying Party) • ユーザーの登録、認証を⾏うウェブサイト、または、事業者  認証器(Authenticator) • キーペアの管理を行う • 外部認証器と内部認証器がある
  11. 11. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 11 利便性  認証行為が容易  複数のパスワードを覚える負担を軽減
  12. 12. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 12 認証行為が容易  生体認証の導入 • 指紋・虹彩・顔・声紋など  認証器を指定・選択できるポリシー • 認証器の多様性 • 認証器の選択
  13. 13. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 13 複数のパスワードを覚える負担を軽減  パスワード(記憶) • 本人のみが記憶している情報  認証器(所持) • 本人のみが所持している物 • 認証器が利用者本人を検証する機能を持つ
  14. 14. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 14 安全性  クレデンシャル情報の通信経路  クレデンシャル情報の安全性  認証器の信頼性
  15. 15. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 15 クレデンシャル情報の通信経路 パスワード認証 リモート認証 (ユーザー名, パスワード) ローカル認証 (指紋など) リモート認証 (署名) FIDO認証モデル User Client User Authenticator client Relying party Relying party
  16. 16. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 16 クレデンシャル情報の安全性 FIDO Authentication Kpub1 Kpub2 RPごとに鍵ペアを生成して登録 rpid1(origin) rpid2(origin) Relying party1 Relying party2 Client  リスト型攻撃に対する耐性  フィッシングに対する耐性 Authenticator Kpriv1 Kpriv2 User Presence
  17. 17. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 17 クレデンシャル情報の安全性(リスト型攻撃対策) Authenticator FIDO Authentication Kpub1 Kpriv1 RPごとに異なる公開鍵を登録 Kpriv2 rpid1(origin) rpid2(origin) Relying party1 Relying party2 Client Kpub2 User Presence
  18. 18. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 18 クレデンシャル情報の安全性(フィッシング対策) FIDO Authentication Kpriv1 RPごとに異なる秘密鍵を保管 Kpriv2 Client User Presence Kpub1Relying party1 Relying party2 Kpub2 Authenticator Relying party3
  19. 19. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 19 認証器の信頼性 Attestation & Metadata Authenticator Registration Attestation privKey Metadata Authentication Keys Signed Attestation Object Relying party Attestation pubKey Attestation Certificate
  20. 20. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 20 FIDOの技術仕様
  21. 21. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 21 FIDOの3つの技術仕様  FIDO UAF(Universal Authentication Framework)  FIDO U2F(Universal 2nd Factor)  FIDO2
  22. 22. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 22 FIDO UAF  パスワードレス型(所持+生体など)  主にスマートフォン端末での利用を想定  生体認証などの認証手段によりパスワードレスを実現 https://www.slideshare.net/FIDOAlliance/fido-83445442
  23. 23. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 23 FIDO U2F  パスワード補完型(記憶+所持)  主にPC上でWebブラウザの利用を想定した二要素認証  着脱方式と無線方式に対応 https://www.slideshare.net/FIDOAlliance/fido-83445442
  24. 24. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 24 UAFとU2F  ユースケースが異なる • UAF(FIDOクライアント=アプリ) • U2F(ブラウザから利用できるが二要素認証)  ブラウザからパスワードレス認証を!! https://www.slideshare.net/FIDOAlliance/fido-83445442
  25. 25. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 25 FIDO2 FIDO認証対応プラットフォームの拡大 Web Authentication API ブラウザからクレデンシャルにアクセスするAPI CTAP クライアントと外部認証器間の通信をサポートするプロトコル https://www.slideshare.net/FIDOAlliance/fido-psd2-solving-the-strong-customer-authentication-challenge-in-europe
  26. 26. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 26 Web Authentication API ブラウザからクレデンシャルにアクセスするAPI  ブラウザの標準インターフェース  Credential Management API の拡張  登録 : navigator.credentials.create()  認証 : navigator.credentials.get()
  27. 27. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 27 CTAP クライアントと外部認証器間の通信をサポートするプロトコル  物理的に異なるクライアントと外部認証器が連携  USB・BLE・NFC などをサポート USB, BLE, NFC, Authenticator client
  28. 28. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 28 様々な認証器に対応 https://www.slideshare.net/FIDOAlliance/fido-83445442
  29. 29. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 29 デモ
  30. 30. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 30 Web Authentication(登録)
  31. 31. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 31 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など) 検証 公開鍵の保存
  32. 32. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 32 実装範囲 Authenticator Client Relying party Web Authentication API 実装が必要な箇所 ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  33. 33. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 33 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  34. 34. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 34 ユーザー名の入力  フォームからユーザー名を取得  ユーザー名を送信してチャレンジなどの情報を要求
  35. 35. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 35 ユーザー名の送信 fetch('/webauthn/register', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: this.username.value, name: this.name.value }) }) サンプル  フォームからユーザー名を取得  ユーザー名を送信してチャレンジなどの情報を要求
  36. 36. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 36 challengeの送信 { // random number challenge: randomBase64URLBuffer(32), rp: { name: "FIDO Examples Corporation” }, user: { id: id, name: username, displayName: displayName }, pubKeyCredParams: [ { type: "public-key", alg: -7 // "ES256" IANA COSE Algorithms registry } ] } サンプル
  37. 37. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. Web Authentication API 37 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  38. 38. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 38 navigator.credentials.create() navigator.credentials.create({ publicKey: { rp: { id: "example.com”, name: "Acme" }, user: { id: new Uint8Array(16), name: "john.p.smith@example.com", displayName: "John P. Smith " }, pubKeyCredParams: [{ type: "public-key", alg: -7 }], attestation: "direct", timeout: 60000, // must be a cryptographically random number sent from a server challenge: new Uint8Array([ 0x8C, 0x0A, 0x26, 0xFF, 0x22, 0x91, 0xC1, 0xE9, ... ]).buffer } }) サンプル
  39. 39. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 39 Parameter  rp [Object] (必須) • Relying partyに関する情報  user [Object](必須) • Credentialが紐づくユーザー情報  challenge[ArrayBuffer] (必須) • サーバーで生成した乱数  pubKeyCredParams[Object] (必須) • Credentialのタイプとアルゴリズムの指定(typeはpublic-key固定)  timeout [Int] • ユーザーの入力待機時間  attestation [String] • Authenticatorの出どころを検証するかどうか  authenticatorSelection [Object] • 認証器への要求事項
  40. 40. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 40 navigator.credentials.create()
  41. 41. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 41 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  42. 42. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 42 AuthenticatorAttestationResponse { // credential identifier on the device "rawId": "imCIoe8U_N9M1rTGeCqJ96TAu5uqSPa7YUzd ... ", "id": ” imCIoe8U_N9M1rTGeCqJ96TAu5uqSPa7YUzdh7qq ... ", // attestation data "response": { "clientDataJSON": ”eyJjaGFsbGVuZ2UiOiJJSFdtWjFPa1MydDZLaH ... ”, "attestationObject": ”o2NmbXRoZmlkby11MmZnYXR0U3RtdKJjc2 ... " }, // extensions results struct "getClientExtensionResults": {}, //  type of credential "type": "public-key” } サンプル
  43. 43. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 43 clientDataJSON { // random number "challenge": "IHWmZ1OkS2t6KhvX-koNxutkYuMVEunCjYNSXXgAxvU", // origin of the website "origin": "http://localhost:3000", // type of the call. "type": "webauthn.create” } サンプル
  44. 44. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 44 attestationObject  CBOR(Concise Binary Object Representation) • JSONフォーマットをバイナリで表現 • JSONよりもサイズが小さい const cbor = require('cbor'); . . . let attestationBuffer = base64url.toBuffer(webAuthnResponse.response.attestationObject); let ctapMakeCredResp = cbor.decodeAllSync(attestationBuffer)[0]; 公開鍵などを含むCBORでエンコードされたデータ サンプル
  45. 45. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 45 attestationObject { // attestation format "fmt": ”packed", // raw buffer struct containing user info "authData": "9569088f1ecee3232954035dbd10d7cae3 ... ", // attestation statement data "attStmt": { // signature "sig": "3046022100db3162cfa7b5dbd78c46864e5f9 ... ", // X.509 Certificate Chain "x5c": [ "3082013c3081e4a003020102020a395187893878526 ... ” ] } } サンプル 公開鍵などを含むCBORでエンコードされたデータ
  46. 46. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 46 authData https://medium.com/@herrjemand/verifying-fido2-responses-4691288c8770 ユーザーの情報を含むバイナリデータ
  47. 47. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 47 authDataのパース let parseMakeCredAuthData = (buffer) => { let rpIdHash = buffer.slice(0, 32); buffer = buffer.slice(32); let flagsBuf = buffer.slice(0, 1); buffer = buffer.slice(1); let flags = flagsBuf[0]; let counterBuf = buffer.slice(0, 4); buffer = buffer.slice(4); let counter = counterBuf.readUInt32BE(0); let aaguid = buffer.slice(0, 16); buffer = buffer.slice(16); let credIDLenBuf = buffer.slice(0, 2); buffer = buffer.slice(2); let credIDLen = credIDLenBuf.readUInt16BE(0); let credID = buffer.slice(0, credIDLen); buffer = buffer.slice(credIDLen); let COSEPublicKey = buffer; return {rpIdHash, flagsBuf, flags, counter, counterBuf, aaguid, credID, credIDLen, credIDLenBuf, COSEPublicKey} } サンプル
  48. 48. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 48 authDataのパース結果 { // hash of the rpId rpIdHash: <Buffer 49 96 0d e5 88 0e 8c 68 74 34 17 0f 64 76 60 5b 8f ... >, // state of the authenticator during the authentication flags: 65, flagsBuf: <Buffer 41>, // 4byte counter counter: 53, counterBuf: <Buffer 00 00 00 35>, // authenticator attestation identifier  aaguid: <Buffer f8 a0 11 f3 8c 0a 4d 15 80 06 17 11 1f 9e dc 7d>, // credential Identifier credID: <Buffer de 13 93 92 33 87 5a 0e 89 1b de 60 dc 43 1f 89 8c ... >, credIDLenBuf: <Buffer 00 40>, credIDLen: 64, // COSE encoded public key COSEPublicKey: <Buffer a5 01 02 03 26 20 01 21 58 20 36 25 71 4a ... > } サンプル
  49. 49. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 49 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  50. 50. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 50 Verify Attestation  challenge、origin、typeの検証  flagsの検証  signatureの検証
  51. 51. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 51 challengeの検証 router.post('/response', (request, response) => { let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); if(clientData.challenge !== request.session.challenge) { response.json({ 'status': 'failed', 'message': 'Challenges don¥'t match!’ }) } . . . }) サンプル clientDataJSON内のchallengeを検証
  52. 52. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 52 originの検証 router.post('/response', (request, response) => { let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); . . . if(clientData.origin !== config.origin) { response.json({ 'status': 'failed', 'message': 'Origins don¥'t match!’ }) } }) サンプル clientDataJSON内のoriginを検証
  53. 53. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 53 typeの検証 . . . let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); if(clientData.type !== 'webauthn.create') { . . . } }) サンプル clientDataJSON内のtypeがwebauthn.createであるか確認
  54. 54. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 54 Verify Attestation  challenge、origin、typeの検証  flagsの検証  signatureの検証
  55. 55. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 55 flagsの検証 AuthenticatorでのUP、UVの結果  UP : User Presence • ユーザーの存在確認(必須)  UV : User Verification • ユーザーの認証(任意) https://slides.com/fidoalliance/jan-2018-fido-seminar-webauthn-tutorial#/
  56. 56. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 56 flagsの検証 let authrDataStruct = parseMakeCredAuthData(ctapMakeCredResp.authData); if(!(authrDataStruct.flags & 0x01)) throw new Error('User was NOT presented durring authentication!'); サンプル AuthenticatorでのUP、UVの結果  UP : User Presence • ユーザーの存在確認(必須)  UV : User Verification • ユーザーの認証(任意)
  57. 57. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 57 Verify Attestation  challenge、origin、typeの検証  flagsの検証  signatureの検証
  58. 58. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 58 signatureの検証  Attestation Certificateの取得  authDataのパラメーターとclientDataJSONのハッシュ値を連結  attStmtからsignatureを取得  signatureを検証
  59. 59. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 59 Attestation Certificateの取得  authData内にあるattSmtのx5c(X.509 Certificate Chain)  PEM形式に変換する • Base64エンコード • 64文字ごとに改行コードをいれる • ヘッダとフッタを入れる let ASN1toPEM = (pkBuffer) => { let type; . . . type = 'CERTIFICATE'; } let b64cert = pkBuffer.toString('base64'); let PEMKey = ''; for(let i = 0; i < Math.ceil(b64cert.length / 64); i++) { let start = 64 * i; PEMKey += b64cert.substr(start, 64) + '¥n'; } PEMKey = `-----BEGIN ${type}-----¥n` + PEMKey + `-----END ${type}-----¥n`; return PEMKey } サンプル
  60. 60. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 60 signatureの検証 . . . let attestationBuffer = base64url.toBuffer(attestationObject); let ctapMakeCredResp = cbor.decodeAllSync(attestationBuffer)[0]; let authrDataStruct = parseMakeCredAuthData(ctapMakeCredResp.authData); let clientDataHash = hash(base64url.toBuffer(clientDataJSON)) // Attestation Certificateの取得 let PEMCertificate = ASN1toPEM(ctapMakeCredResp.attStmt.x5c[0]); // authDataのパラメーターとclientDataJSONのハッシュ値を連結 let signatureBase = Buffer.concat([ authrDataStruct.rpIdHash, authrDataStruct.flagsBuf, authrDataStruct.counterBuf, authrDataStruct.aaguid, authrDataStruct.credIDLenBuf, authrDataStruct.credID, authrDataStruct.COSEPublicKey, clientDataHash ]); // attStmtからsignatureの取得 let signature = ctapMakeCredResp.attStmt.sig; // 検証 response.verified = crypto .createVerify('SHA256') .update(signatureBase) .verify(PEMCertificate, signature); } サンプル
  61. 61. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 61 Verify Attestation  challenge、origin、typeの検証  flagsの検証  signatureの検証
  62. 62. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 62 登録成功!!
  63. 63. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 63 登録フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジなど Attestation response 検証 公開鍵の保存 鍵ペアの生成 Attestation response チャレンジ・RPの情報・ユーザーの情報 (署名・証明書・公開鍵など) (署名・証明書・公開鍵など)
  64. 64. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 64 publicKeyの保存 let verifyAuthenticatorAttestationResponse = (webAuthnResponse) => { . . . let authrDataStruct = parseMakeCredAuthData(ctapMakeCredResp.authData); // COSE PublicKeyをPKCS形式に変換 let publicKey = COSEECDHAtoPKCS(authrDataStruct.COSEPublicKey) let verified = verifySignature(signature, signatureBase, PEMCertificate) if(verified) { // publicKeyなどを保存 response.authrInfo = { fmt: ’packed', publicKey: base64url.encode(publicKey), counter: authrDataStruct.counter, credID: base64url.encode(authrDataStruct.credID) } } } return response } サンプル  COSE(CBOR Object Signing and Encryption) • 暗号鍵を表現するためのJSONをCBORエンコードしたフォーマット • COSEから取得したxとyを連結し、先頭に0x04を加えるとPublicKeyになる
  65. 65. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 65 publicKeyの保存  COSE(CBOR Object Signing and Encryption) • 暗号鍵を表現するためのJSONをCBORエンコードしたフォーマット • COSEから取得したxとyを連結し、先頭に0x04を加えるとPublicKeyになる // result of COSE parse { 1: kty=2, 3: alg=-7, -1: crv=1, -2: x, -3: y, } サンプル
  66. 66. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 66 publicKeyの保存  COSE(CBOR Object Signing and Encryption) • 暗号鍵を表現するためのJSONをCBORエンコードしたフォーマット • COSEから取得したxとyを連結し、先頭に0x04を加えるとPublicKeyになる const cbor = require('cbor'); . . . let COSEECDHAtoPKCS = (COSEPublicKey) => { let coseStruct = cbor.decodeAllSync(COSEPublicKey)[0]; let tag = Buffer.from([0x04]); let x = coseStruct.get(-2); let y = coseStruct.get(-3); return Buffer.concat([tag, x, y]) } サンプル
  67. 67. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 67 Web Authentication(認証)
  68. 68. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 68 認証フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  69. 69. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 69 実装範囲 Authenticator Client Relying party Web Authentication API 実装が必要な箇所 ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  70. 70. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 70 認証フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  71. 71. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 71 ユーザー名の入力
  72. 72. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 72 ユーザー名の送信 fetch('/webauthn/login', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: this.username.value }) }) サンプル
  73. 73. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 73 challengeの送信 let generateServerGetAssertion = (authenticators) => { let allowCredentials = []; for(let authr of authenticators) { allowCredentials.push({ type: 'public-key', id: authr.credID, transports: ['usb', 'nfc', 'ble'] }) } return { // random number challenge: randomBase64URLBuffer(32), allowCredentials: allowCredentials } } サンプル
  74. 74. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. Web Authentication API 74 実装範囲 Authenticator Client Relying party ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  75. 75. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 75 navigator.credentials.get() navigator.credentials.get({ publicKey: { timeout: 60000, challenge: new Uint8Array([ 0x79, 0x50, 0x68, 0x71, 0xDA, 0xEE, 0xEE, 0xB9, 0x94, 0xC3, 0xC2, ... ]).buffer, allowCredentials: [{ id: cred.rawId, transports: ["usb", "nfc", "ble"], type: "public-key" }] }, }) サンプル
  76. 76. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 76 Parameter  challenge [ArrayBuffer] (必須) • サーバーで生成した乱数  timeout [Int] • ユーザーの入力待機時間  allowCredentials [Array] • ユーザーに紐づくCredentialのidリスト  rpId [String] • rpIdの指定(登録時と同じ値を指定)  userVerification [String] • ユーザーに紐づくCredentialのリスト
  77. 77. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 77 navigator.credentials.get()
  78. 78. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 78 実装範囲 Authenticator Client Relying party ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  79. 79. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 79 AuthenticatorAssertionResponse { // credential identifier on the device "rawId": "imCIoe8U_N9M1rTGeCqJ96TAu5uqSPa7YUzd ... " , "id": "imCIoe8U_N9M1rTGeCqJ96TAu5uqSPa7YUzdh7qq ... ", // assertion data "response": { "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAALQ", "signature": "MEUCIQCFOqnsAFZLQmcPt2qSjnCb403SisGEASSjT3fOPuD5JgIgF ...", "userHandle": "", "clientDataJSON": "eyJjaGFsbGVuZ2UiOiJDUXF5aUlrQ00yWEtvaHVSdlNqTEFoN ...” }, // extensions results struct "getClientExtensionResults": {}, // type of credential "type": "public-key” } サンプル
  80. 80. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 80 authenticatorData https://slides.com/fidoalliance/jan-2018-fido-seminar-webauthn-tutorial#/ ユーザーの情報を含むバイナリデータ
  81. 81. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 81 authenticatorDataのパース let parseGetAssertAuthData = (buffer) => { let rpIdHash = buffer.slice(0, 32); buffer = buffer.slice(32); let flagsBuf = buffer.slice(0, 1); buffer = buffer.slice(1); let flags = flagsBuf[0]; let counterBuf = buffer.slice(0, 4); buffer = buffer.slice(4); let counter = counterBuf.readUInt32BE(0); return {rpIdHash, flagsBuf, flags, counter, counterBuf} } サンプル
  82. 82. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 82 authenticatorDataのパース結果 { // hash of the rpId rpIdHash: <Buffer 49 96 0d e5 88 0e 8c 68 74 34 17 0f 64 76 60 5b 8f e4 ae b9 a2 86 32 c7 99 5c f3 ba 83 1d 97 63>, // state of the authenticator during the authentication flags: 1, flagsBuf: <Buffer 01>, // 4byte counter counter: 68, counterBuf: <Buffer 00 00 00 44> } サンプル
  83. 83. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 83 認証フロー(概略) Authenticator Client Relying party ユーザー名 チャレンジやユーザーの情報など Assertion response 検証 署名の生成 Assertion response チャレンジ・RPの情報・ユーザーの情報 (署名など) (署名など)
  84. 84. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 84 Verify Assertion  challenge、origin、typeの検証  flagsの検証  signatureの検証  counterの検証と更新
  85. 85. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 85 challengeの検証 router.post('/response', (request, response) => { let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); if(clientData.challenge !== request.session.challenge) { response.json({ 'status': 'failed', 'message': 'Challenges don¥'t match!’ }) } . . . }) サンプル clientDataJSONとセッションなどに保存していたchallengeを比較
  86. 86. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 86 originの検証 router.post('/response', (request, response) => { let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); . . . if(clientData.origin !== config.origin) { response.json({ 'status': 'failed', 'message': 'Origins don¥'t match!’ }) } }) サンプル clientDataJSONとサーバーのコンフィグなどから取得したoriginを比較
  87. 87. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 87 typeの検証 . . . let webauthnResp = request.body let clientData = JSON.parse(base64url.decode(webauthnResp.response.clientDataJSON)); if(clientData.type !== 'webauthn.get') { . . . } }) サンプル clientDataJSONのtypeがwebauthn.getであるか確認
  88. 88. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 88 Verify Assertion  challenge、origin、typeの検証  flagsの検証  signatureの検証  counterの検証と更新
  89. 89. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 89 flagsの検証 let authrDataStruct = parseMakeCredAuthData(ctapMakeCredResp.authData); if(!(authrDataStruct.flags & 0x01)) throw new Error('User was NOT presented durring authentication!'); サンプル AuthenticatorでのUP、UVの結果を検証
  90. 90. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 90 Verify Assertion  challenge、origin、typeの検証  flagsの検証  signatureの検証  counterの検証と更新
  91. 91. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 91 signatureの検証  Authenticatorの検索  PublicKeyの取得  authenticatorDataのパラメータとclientDataJSONのハッシュ値を連結  AuthenticatorAssertionResponseからsignatureを取得  signatureを検証
  92. 92. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 92 Authenticatorの検索 let findAuthr = (credID, authenticators) => { for(let authr of authenticators) { if(authr.credID === credID) return authr } throw new Error(`Unknown authenticator with credID ${credID}!`) } サンプル CredentialIdを元にAuthenticatorを検索する
  93. 93. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 93 publicKeyの取得  登録時に保存したpublicKeyを取りだす  PEM形式に変換する • 26バイトのメタデータ(固定)を付与する • Base64エンコード • 64文字ごとに改行コードをいれる • ヘッダとフッタを入れる
  94. 94. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 94 publicKeyの取得 let ASN1toPEM = (pkBuffer) => { . . . // 26byteのメタデータを追加 pkBuffer = Buffer.concat([ new Buffer.from("3059301306072a8648ce3d020106082a8648ce3d030107034200", "hex"), pkBuffer ]); type = 'PUBLIC KEY'; . . . // Base64エンコード let b64cert = pkBuffer.toString('base64'); let PEMKey = ''; for(let i = 0; i < Math.ceil(b64cert.length / 64); i++) { let start = 64 * i; // 改行コードの追加 PEMKey += b64cert.substr(start, 64) + '¥n'; } // ヘッダとフッタの追加 PEMKey = `-----BEGIN ${type}-----¥n` + PEMKey + `-----END ${type}-----¥n`; return PEMKey } サンプル
  95. 95. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 95 signatureの検証 let verifyAuthenticatorAssertionResponse = (webAuthnResponse, authenticators) => { . . . let authenticatorData = base64url.toBuffer(webAuthnResponse.response.authenticatorData); let authrDataStruct = parseGetAssertAuthData(authenticatorData); let clientDataHash = hash(base64url.toBuffer(webAuthnResponse.response.clientDataJSON)) // authenticatorDataとclientDataJSONのハッシュ値を連結 let signatureBase = Buffer.concat([ authrDataStruct.rpIdHash, authrDataStruct.flagsBuf, authrDataStruct.counterBuf, clientDataHash ]); // 登録時に保存した公開鍵を取得 let publicKey = ASN1toPEM(base64url.toBuffer(authr.publicKey)); // navigator.credentials.get()の戻り値のsignatureを取得 let signature = base64url.toBuffer(webAuthnResponse.response.signature); // 検証 response.verified = crypto .createVerify('SHA256') .update(signatureBase) .verify(publicKey, signature); . . . } サンプル
  96. 96. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 96 Verify Assertion  challenge、origin、typeの検証  flagsの検証  signatureの検証  counterの検証と更新
  97. 97. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 97 counterの検証と更新 let verifyAuthenticatorAssertionResponse = (webAuthnResponse, authenticators) => { . . . if(response.verified) { if(response.counter <= authr.counter) throw new Error('Authr counter did not increase!'); authr.counter = authrDataStruct.counter } } . . . } サンプル authenticatorDataのcounterを検証
  98. 98. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 98 Verify Assertion  challenge、origin、typeの検証  flagsの検証  signatureの検証  counterの検証と更新
  99. 99. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 99 認証成功!!
  100. 100. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 100 まとめ
  101. 101. まとめ Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 101  パスワード認証は利便性と安全性に問題  FIDO認証は公開鍵暗号を応用しパスワード認証の課題を解消  FIDO2プロジェクトにより認証対応プラットフォームの拡大
  102. 102. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 102 RPのサンプル実装 様々な言語で実装されている  Node.js : https://github.com/fido-alliance/webauthn-demo  Python : https://github.com/duo-labs/py_webauthn  Ruby : https://github.com/cedarcode/webauthn-ruby  Go : https://github.com/duo-labs/webauthn  Java : https://github.com/Yubico/java-webauthn-server この他にもいっぱい!! https://github.com/apowers313/fido2-server-demo/
  103. 103. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved. 103 参考 • FIDO認証の概要説明 https://www.slideshare.net/FIDOAlliance/fido-83445442?ref=https://fidoalliance.org/presentations/ • Webauthn-isig http://slides.com/herrjemand/webauthn-isig • INTRODUCTION TO FIDO ALLIANCE https://www.slideshare.net/FIDOAlliance/introduction-to-fido-alliance-66730790 • MDN web docs WebAuthentication API https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API • Welcome to WebAuthn workshop https://slides.com/fidoalliance/jan-2018-fido-seminar-webauthn-tutorial#/ • Verifying WebAuthn/FIDO2 responses https://medium.com/@herrjemand/verifying-fido2-responses-4691288c8770 • Verifying FIDO-U2F Attestation https://medium.com/@herrjemand/verifying-fido-u2f-attestations-in-fido2-f83fab80c355 • WebAuthn from the relying-party view https://speakerdeck.com/ynojima/webauthn-from-the-relying-party-view
  104. 104. Copyright (C) 2018 Yahoo Japan Corporation. All Rights Reserved.

×