Password-less Web applications created with WebAuthn.

Password-less Web applications created with WebAuthn.

# WebAuthn で作るパスワードレスWEBアプリケーション

デモのURLはこちら:https://laravel-webauthn-demo.k-masatany.com/
- しばらく放置しているので、お試しください。
- Windows Hello は起動しますが、証明書のパースを実装していないのでエラーが起きますw

22e96aa0059e6788659d156463820248?s=128

k-masatany

June 29, 2019
Tweet

Transcript

  1. Password-less Web applications created with WebAuthn. WebAuthn Ͱ࡞ΔύεϫʔυϨεWEBΞϓϦέʔγϣϯ 2019/06/29 PHP

    Conference Fukuoka 2019 Fusic Co., Ltd Kensuke Masatani (@k_masatany)
  2. ࣗݾ঺հ • ੓୩ ݡ༞ (@k_masatany) • גࣜձࣾ Fusic ॴଐ •

    ݩ૊ΈࠐΈܥΤϯδχΞ • ࠓ͸ Laravel ϝΠϯͷ PHPer • AWS ΋ಘҙʢͰ΋͍ͭઌ೔ೝఆ੾ΕͪΌ͍·ͨ͠ʣ • ࠷ۙ͸αʔόʔϨεͳ Laravel Λಈ͔ͯ͠༡ΜͰ͍Δ
  3. ΞδΣϯμ ✅ ࣗݾ঺հ WebAuthn ͱ͸ ɾ WebAuthn ͷ۩ମతͳೝূಈ࡞ ɾ WebAuthn

    Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ
  4. WebAuthn ͱ͸

  5. WebAuthn ͱ͸ • ਖ਼໊ࣜশ͸ Web Authentication • ϒϥ΢βΛར༻͠ύεϫʔυϨεೝূΛߦ͏ͨΊͷ ࢓༷ʢن֨ʣ͓ΑͼͦͷAPI •

    2019೥3݄ קࠂԽ → ۙʑඪ४Խʢͷ͸ͣʣ https://www.w3.org/2019/03/pressrelease-webauthn-rec.html • ओཁϒϥ΢βͰ͸͢Ͱʹ WebAuthn ͕࣮૷ࡁΈ • WebAuthn = FIDO + CTAP
  6. WebAuthn ͱ͸ • ਖ਼໊ࣜশ͸ Web Authentication • ϒϥ΢βΛར༻͠ύεϫʔυϨεೝূΛߦ͏ͨΊͷ ࢓༷ʢن֨ʣ͓ΑͼͦͷAPI •

    2019೥3݄ קࠂԽ → ۙʑඪ४Խʢͷ͸ͣʣ https://www.w3.org/2019/03/pressrelease-webauthn-rec.html • ओཁϒϥ΢βͰ͸͢Ͱʹ WebAuthn ͕࣮૷ࡁΈ • WebAuthn = FIDO + CTAP
  7. WebAuthn ϒϥ΢βରԠঢ়گʢ2019/06/28࣌఺ʣ https://caniuse.com/#feat=webauthn

  8. WebAuthn ͱ͸ • ਖ਼໊ࣜশ͸ Web Authentication API • ϒϥ΢βΛར༻͠ύεϫʔυϨεೝূΛߦ͏ͨΊͷ ࢓༷ʢن֨ʣ͓ΑͼͦͷAPI

    • 2019೥3݄ קࠂԽ → ۙʑඪ४Խʢͷ͸ͣʣ https://www.w3.org/2019/03/pressrelease-webauthn-rec.html • ओཁϒϥ΢βͰ͸͢Ͱʹ WebAuthn ͕࣮૷ࡁΈ • WebAuthn = FIDO + CTAP
  9. WebAuthn = FIDO2 + CTAP FIDOʢFast IDentity Onlineʣ • FIDO

    Alliance͕ਪਐ͢Δೝূٕज़ • https://fidoalliance.org • Webϒϥ΢β্Ͱࢦ໲ೝূͳͲͷੜମೝূɺ USBΩʔͳͲͷ෺ཧΩʔΛར༻͢ΔͨΊͷٕज़ɻ
  10. WebAuthn = FIDO2 + CTAP CTAPʢClient to Authentication Protocolʣ •

    FIDO ͷن֨ͷҰͭ • ΫϥΠΞϯτͱೝূσόΠεؒͷ௨৴ϓϩτίϧ • Webϒϥ΢βͱೝূػثͷؒͰ࢖༻͢Δ௨৴಺༰Λ نఆͯ͠ɺAPIͱͯ͠੔උɻ • CTAPʹΑΓɺFIDO४ڌͷೝূػثͰ͋Ε͹ɺ ΞϓϦέʔγϣϯ͔Βͷར༻͕༰қʹͳΔʢ͸ͣʣɻ
  11. ύεϫʔυೝূͷԿ͕໰୊͔

  12. ύεϫʔυೝূͷ՝୊ ௕͍ύεϫʔυ͸ هԱɾೖྗ͕໘౗

  13. ύεϫʔυೝূͷ՝୊ ୹͍ύεϫʔυΛ ࢖ͬͯ͠·͏

  14. ύεϫʔυೝূͷ՝୊ ؆୯ʹഁΒΕͯ͠·͏

  15. ύεϫʔυೝূͷ՝୊ ௕͍ύεϫʔυ͸ هԱɾೖྗ͕໘౗

  16. ύεϫʔυೝূͷ՝୊ ผαʔϏεͰಉ͡ύεϫʔυΛ ࢖ͬͯ͠·͏

  17. ύεϫʔυೝূͷ՝୊ Ұͭྲྀग़ͰશαʔϏε͕ ߈ܸͷ㕒৯ʹ

  18. ύεϫʔυೝূͷ՝୊ • ೖྗ΋؅ཧ΋໘౗

  19. ύεϫʔυೝূͷ՝୊ • ೖྗ΋؅ཧ΋໘౗ • ໘౗Ώ͑ʹ੬ऑͳύεϫʔυΛར༻

  20. ύεϫʔυೝূͷ՝୊ • ೖྗ΋؅ཧ΋໘౗ • ໘౗Ώ͑ʹ੬ऑͳύεϫʔυΛར༻ • ໘౗Ώ͑ʹైḤͳ؅ཧ͕͞Εͯ͠·͏

  21. ύεϫʔυೝূͷ՝୊ • ೖྗ΋؅ཧ΋໘౗ • ໘౗Ώ͑ʹ੬ऑͳύεϫʔυΛར༻ • ໘౗Ώ͑ʹైḤͳ؅ཧ͕͞Εͯ͠·͏ ɹ ɹͦ΋ͦ΋ɺ ɹύεϫʔυͱ͍͏໊ͷൿಗ৘ใ͕

    ɹΠϯλʔωοτ্ΛྲྀΕ͍ͯΔ͜ͱ͕໰୊
  22. WebAuthn ͰͲ͏มΘΔ͔

  23. ύεϫʔυೝূ͔Β WebAuthn ΁ ਓ͕ؒύεϫʔυʢೝূ৘ใʣΛੜ੒͠ͳ͍ ࢦ໲ೝূ إೝূ USBΩʔ

  24. ύεϫʔυೝূ͔Β WebAuthn ΁ ୹͍ύεϫʔυΛ ࢖ͬͯ͠·͏

  25. ύεϫʔυೝূ͔Β WebAuthn ΁ ೝূ৘ใͷ؅ཧ͸ೝূث͕ߦ͏ ʢೝূث಺ʹαʔϏεͱೝূ৘ใͷඥ෇͚Λอଘʣ

  26. ύεϫʔυೝূ͔Β WebAuthn ΁ ผαʔϏεͰಉ͡ύεϫʔυΛ ࢖ͬͯ͠·͏

  27. ͍͍͜ͱ͹͔ΓͰ͸ͳ͍

  28. ύεϫʔυೝূ͔Β WebAuthn ΁ ਓ͕ؒύεϫʔυʢೝূ৘ใʣΛੜ੒͠ͳ͍ ࢦ໲ೝূ إೝূ USBΩʔ

  29. ύεϫʔυೝূ͔Β WebAuthn ΁ ύεϫʔυͷ؅ཧ͸͠ͳ͍͍͕ͯ͘ɺ ೝূثͷ؅ཧ͸͠ͳ͚Ε͹ͳΒͳ͍ ࢦ໲ೝূ إೝূ USBΩʔ

  30. ύεϫʔυೝূ͔Β WebAuthn ΁ ೝূثΛฆࣦͨ࣌͠͸ɺ ࠷ѱͷ৔߹ϩάΠϯͰ͖ͳ͘ͳͬͯ͠·͏ ࢦ໲ೝূ إೝূ USBΩʔ

  31. ύεϫʔυೝূ͔Β WebAuthn ΁ ʢ΋ͷʹ΋ΑΔ͕ʣUSBೝূثͷ౪೉ʹ͋͏ͱɺ ͳΓ͢·͕͠ߦΘΕͯ͠·͏Մೳੑ͕͋Δ USBΩʔ

  32. ύεϫʔυೝূ͔Β WebAuthn ΁ ೝূ৘ใͷ؅ཧ͸ೝূث͕ߦ͏ ʢೝূث಺ʹαʔϏεͱೝূ৘ใͷඥ෇͚Λอଘʣ

  33. ύεϫʔυೝূ͔Β WebAuthn ΁ ಉ͡ϢʔβʔͰ΋ɺ ೝূث͕ҧ͑͹ϩάΠϯͰ͖ͳ͍

  34. ύεϫʔυೝূ͔Β WebAuthn ΁ ʢΞϓϦέʔγϣϯͷ࡞Γํʹґଘ͠·͕͢ʣ Ϣʔβʔొ࿥ͷෑډ͕ߴ͘ͳΔ

  35. ຊ൪ӡ༻Ͱ͸ΞΧ΢ϯτ؅ཧͱ ϦΧόϦͷઃܭ͕؊ʹͳΓͦ͏

  36. ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ WebAuthn ͷ۩ମతͳೝূಈ࡞ ɾ WebAuthn

    Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ
  37. WebAuthn ͷ۩ମతͳೝূಈ࡞

  38. WebAuthn ͷ 3େཁૉ ໊শ ໾ׂ $MJFOU ʢΫϥΠΞϯτʣ 8FC"VUIOΛ࣮ߦ͢Δϒϥ΢β 8FC"VUIOͷ"1*ʹରԠ͍ͯ͠Δඞཁ͕͋Δ "VUIFOUJDBUPS

    ʢೝূثʣ ࣮ࡍʹຊਓͷ֬ೝͱΩʔϖΞͷੜ੒Λߦ͏ ֎෦ೝূثʢ64#Ωʔɺ:VCJLFZͳͲʣ ಺෦ೝূثʢεϚϗ΍.BDͷࢦ໲ೝূͳͲʣ 3FMZJOH1BSUZ ʢ31ʣ ࣮ࡍʹϢʔβʔͷొ࿥΍؅ཧΛߦ͏αΠτ ೝূث͔Βૹ৴͞ΕΔެ։伴Λอଘ
  39. Ϣʔβʔొ࿥࣌ ʢUser Registrationʣ

  40. Client Authenticator RP

  41. Client Authenticator RP ᶃ Request Challenge Ϣʔβʔొ࿥ϑΥʔϜʹσʔλΛೖྗ RP΁σʔλΛૹ৴

  42. Ϣʔβʔࣝผ৘ใɺRP৘ใɺ νϟϨϯδΛૹ৴ Client Authenticator RP ᶃ Request Challenge ᶄ Response

    Challenge
  43. Client Authenticator RP ᶃ Request Challenge ᶄ Response Challenge ᶅ

    Request KeyPair RP͔Βड͚औͬͨ৘ใΛݩʹ ೝূثʹ伴ͷੜ੒ΛϦΫΤετ
  44. Client Authenticator RP ᶃ Request Challenge ᶄ Response Challenge ᶅ

    Request KeyPair ᶆ Verify User ೝূث͕Ϣʔβʔͷ֬ೝΛ࣮ߦ
  45. Client KeyPair Authenticator RP ᶃ Request Challenge ᶄ Response Challenge

    ᶅ Request KeyPair ᶆ Verify User ᶇ Create KeyPair Ϣʔβʔͷ֬ೝ͕औΕͨΒ ΩʔϖΞͳͲͷೝূ৘ใΛ࡞੒
  46. Client KeyPair Authenticator RP ᶃ Request Challenge ᶄ Response Challenge

    ᶅ Request KeyPair ᶆ Verify User ᶇ Create KeyPair ᶈ Response AD Authenticator Data ੜ੒ͨ͠ೝূ৘ใΛΫϥΠΞϯτ΁
  47. Client KeyPair Authenticator RP ᶃ Request Challenge ᶄ Response Challenge

    ᶅ Request KeyPair ᶆ Verify User ᶇ Create KeyPair ᶈ Response AD Authenticator Data ᶉ Send AD ೝূ৘ใΛRP΁
  48. Client KeyPair Authenticator RP ᶃ Request Challenge ᶄ Response Challenge

    ᶅ Request KeyPair ᶆ Verify User ᶇ Create KeyPair ᶈ Response AD Authenticator Data ᶉ Send AD ᶊ Verify AD ೝূ৘ใΛݕূ Ϣʔβʔͷ֬ೝ͕औΕͨΒɺެ։伴Λੜ੒
  49. Client KeyPair ᶇ Create KeyPair ᶉ Send AD ᶆ Verify

    User ᶃ Request Challenge ᶄ Response Challenge ᶊ Verify AD ᶈ Response AD ᶅ Request KeyPair Authenticator Data Authenticator RP ᶋ Create User Ϣʔβʔొ࿥ ੜ੒ͨ͠ެ։伴͸Ϣʔβʔʹඥ͚ͮͯอଘ
  50. Client KeyPair ᶇ Create KeyPair ᶉ Send AD ᶆ Verify

    User ᶃ Request Challenge ᶄ Response Challenge ᶊ Verify AD ᶈ Response AD ᶅ Request KeyPair Authenticator Data Authenticator RP ᶋ Create User ొ࿥׬ྃ
  51. Ϣʔβʔೝূ࣌ ʢUser Authenticationʣ

  52. Client Authenticator RP

  53. Client ᶃ Request Challenge & KeyID Authenticator RP ϩάΠϯϑΥʔϜʹσʔλΛೖྗ RP΁σʔλΛૹ৴

  54. Client ᶃ Request Challenge & KeyID Authenticator RP ᶄ Response

    Challenge ϩάΠϯର৅ͷϢʔβʔͷσʔλΛݕࡧ νϟϨϯδͱͱ΋ʹࣝผ৘ใΛૹ৴
  55. Client ᶃ Request Challenge & KeyID Authenticator RP ᶄ Response

    Challenge ᶅ Request Signature ϢʔβʔσʔλΛೝূثʹૹ৴ͯ͠ ॺ໊ͷੜ੒ΛϦΫΤετ
  56. Client ᶆ Verify User ᶃ Request Challenge & KeyID Authenticator

    RP ᶄ Response Challenge ᶅ Request Signature ೝূث͕Ϣʔβʔͷ֬ೝΛ࣮ߦ
  57. Client Signeture ᶇ Create Signature ᶆ Verify User ᶃ Request

    Challenge & KeyID Authenticator RP ᶄ Response Challenge ᶅ Request Signature Ϣʔβʔͷ֬ೝ͕औΕͨΒ ൿີ伴Ͱॺ໊Λ࡞੒
  58. Client Signeture ᶇ Create Signature ᶆ Verify User ᶃ Request

    Challenge & KeyID ᶄ Response Challenge ᶈ Response AD Authenticator Data Authenticator RP ᶅ Request Signature ੜ੒ͨ͠ॺ໊ΛΫϥΠΞϯτ΁
  59. ॺ໊ΛRP΁ Client Signeture ᶇ Create Signature ᶉ Send AD ᶆ

    Verify User ᶃ Request Challenge & KeyID ᶈ Response AD Authenticator Data Authenticator RP ᶄ Response Challenge ᶅ Request Signature
  60. Client Signeture ᶇ Create Signature ᶉ Send AD ᶆ Verify

    User ᶃ Request Challenge & KeyID ᶊ Verify Signature ᶈ Response AD Authenticator Data Authenticator RP ᶄ Response Challenge ᶅ Request Signature ॺ໊Λެ։伴Ͱݕূ
  61. Client Signeture ᶇ Create Signature ᶉ Send AD ᶆ Verify

    User ᶃ Request Challenge & KeyID ᶊ Verify Signature ᶈ Response AD Authenticator Data Authenticator RP ᶋ Authenticate User ᶄ Response Challenge ᶅ Request Signature ϩάΠϯ੒ޭ
  62. ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ WebAuthn

    Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ
  63. WebAuthn Λ -BSBWFMʹ૊ΈࠐΜͰΈΔ

  64. σϞ༻ʹ࡞͍ͬͯΔ΋ͷͳͷͰ ࡉ͔͍ποίϛ͸ແ͠ͰΦωγϟε

  65. σϞ༻ʹ࡞͍ͬͯΔ΋ͷͳͷͰ ͜Εݟͯೝূαʔό࡞Βͳ͍ͰͶ

  66. 1. 㙽ʹ΋֯ʹ΋ artisan make:auth σϑΥϧτͷೝূػߏΛϕʔεʹ WebAuthn Λ૊ΈࠐΜͰ͍͖·͢ ಛචࣄ߲͸͋Γ·ͤΜɻ

  67. 2. ύεϫʔυΧϥϜͷຣࡴ database/migrations/2014_10_12_000000_create_users_table.php public function up() { Schema::create('users', function (Blueprint

    $table) { $table->bigIncrements('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); }
  68. database/migrations/2019_06_29_000000_create_public_keys_table.php ͦΕͬΆ͘࡞੒ public function up() { Schema::create('public_keys', function (Blueprint $table)

    { $table->bigIncrements('id'); $table->bigInteger('user_id'); $table->string('type'); $table->string('raw_id'); $table->string('key'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users'); $table->index(['user_id']); }); } 3. 伴อଘ༻ͷςʔϒϧΛ࡞੒
  69. 4. ϧʔςΟϯάΛ௥Ճ routes/web.php ɾmake:auth Ͱ࡞੒͞ΕΔ Controller ʹ௥Ճͷ action Λ࡞੒ ɾjs

    ͕ۤखͳͷͰɺajax Ͱ͸ͳ͘ී௨ʹϨϯμϦϯά͢ΔํࣜͰ࡞੒ ɾ Route::post('/register/confirm', ‘Auth\RegisterController@confirmRegister'); Route::post('/register', ‘Auth\RegisterController@save'); Route::post('/login/confirm', ‘Auth\LoginController@confirmLogin'); Route::post('/login', ‘Auth\LoginController@login');
  70. 5. view ϑΝΠϧͷฤू & ௥Ճ ɾresources/views/auth/register.blade.php ɾresources/views/auth/login.blade.php ɾ΄΅σϑΥϧτͷ··࢖༻ ɾύεϫʔυΛೖྗ͢ΔϑΥʔϜΛ࡟আ ɾPOST

    ઌΛɺઌ΄Ͳ࡞੒ͨ͠ *-confirm ΞΫγϣϯʹมߋ <form method="POST" action="/register/confirm"> <form method="POST" action="/register">
  71. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ https://github.com/web-auth/webauthn-lib ࠓճ͸ web-auth/webauthn-lib Λར༻ͯ͠࡞੒͠·͢

  72. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php RP ʹؔ͢Δ৘ใΛઃఆ public function confirmRegister(Request $request) {

    // RP Entity $rpEntity = new PublicKeyCredentialRpEntity( config('webauthn.rp.name'), //Name config('webauthn.rp.id'), // ID null//Icon );
  73. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ొ࿥͢ΔϢʔβʔʹؔ͢Δ৘ใΛઃఆ // User Entity $userEntity = new

    PublicKeyCredentialUserEntity( $request->email, //Name (string) Str::uuid(), //ID $request->name, //Display name null//Icon );
  74. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php νϟϨϯδΛੜ੒ // Challenge $challenge = random_bytes(32); session(['register.challenge'

    => base64_encode($challenge)]); ɾϥϯμϜͳόΠτྻ ɾޙ΄Ͳݕূ͢ΔͷͰɺηογϣϯ౳ʹอ࣋
  75. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php 伴ੜ੒ͷύϥϝʔλΛઃఆ // Public Key Credential Parameters $publicKeyCredentialParametersList

    = [ new PublicKeyCredentialParameters( ‘public-key', Algorithms::COSE_ALGORITHM_ES256 ), ]; ɾެ։伴ೝূํࣜ ɾES256ͱ͍͏ΞϧΰϦζϜͷΈڐՄ ɾWindows Hello Λ࢖͍͍ͨͳΒ RS256 ΋ڐՄ
  76. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ଞͷ߲໨ΛͳΜ΍͔Μ΍ઃఆ // Timeout $timeout = 10000; //

    Devices to exclude $excludedPublicKeyDescriptors = []; // Authenticator Selection Criteria (we used default values) $authenticatorSelectionCriteria = new AuthenticatorSelectionCriteria(); // Extensions $extensions = new AuthenticationExtensionsClientInputs(); ɹ $extensions->add(new AuthenticationExtension('loc', true));
  77. 6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ࡞੒ͨ͠৘ใΛͻͱ·ͱΊʹͯ͠ view ʹຒΊࠐΜͰϨϯμϦϯά $publicKeyCredentialCreationOptions = new PublicKeyCredentialCreationOptions(

    $rpEntity, $userEntity, $challenge, $publicKeyCredentialParametersList, $timeout, $excludedPublicKeyDescriptors, $authenticatorSelectionCriteria, PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE, $extensions ); return view('auth.register-confirm', compact('publicKeyCredentialCreationOptions'));
  78. 7. 伴Λੜ੒͢ΔͨΊͷεΫϦϓτΛviewʹ௥Ճ resources/views/auth/login-confirm.blade.php αʔόʔͰੜ੒ͨ͠σʔλΛ js ଆͰ࢖͏ͨΊʹௐ੔ <script> let publicKey =

    @php echo json_encode($publicKeyCredentialRequestOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); @endphp function arrayToBase64String(a) { return btoa(String.fromCharCode(...a)); } console.log(publicKey); publicKey.challenge = Uint8Array.from(window.atob(publicKey.challenge), c => c.charCodeAt(0)); publicKey.allowCredentials = publicKey.allowCredentials.map(function (data) { return { ...data, 'id': Uint8Array.from(atob(data.id), c => c.charCodeAt(0)) }; }); https://github.com/web-auth/webauthn-framework/blob/v1.2/doc/ webauthn/PublicKeyCredentialCreation.md#example Λࢀߟʹ࣮૷
  79. 7. 伴Λੜ੒͢ΔͨΊͷεΫϦϓτΛviewʹ௥Ճ resources/views/auth/login-confirm.blade.php APIΛհͯ͠ೝূثʹ伴ੜ੒ϦΫΤετ ʢݟʹͯ͘͘͝ΊΜͳ͍͞ʣ navigator.credentials.get({ publicKey }) .then(data =>

    { let publicKeyCredential = { id: data.id, type: data.type, rawId: arrayToBase64String(new Uint8Array(data.rawId)), response: { authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)), clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)), signature: arrayToBase64String(new Uint8Array(data.response.signature)), userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null } }; document.querySelector("input[name='publicKeyCredential']").value = JSON.stringify(publicKeyCredential); document.getElementById('login').submit(); }, function (error) { window.location = '/login'; });
  80. 8. 伴ݕূ༻ͷΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ϨεϙϯεΛΰϦͬͱղੳ /** * save user */ public

    function save(UserRegisterRequest $request) { $data = $request->publicKeyCredential; $publicKeyCredential = json_decode($data); // Ϩεϙϯε಺ͷ ClientDataJSON Λσίʔυ $clientDataJSON = json_decode(base64_decode($publicKeyCredential->response->clientDataJSON)); // ηογϣϯʹอଘͨ͠ challenge ΛऔΓग़ͯ͠࡟আ $challenge = base64_decode(session('register.challenge')); session()->forget('register.challenge'); // Ϩεϙϯε಺ͷ AttestationObject Λσίʔυ & ύʔε $encodedAttestationObject = base64_decode($publicKeyCredential->response->attestationObject); $attestationObject = CBOREncoder::decode($encodedAttestationObject); $authDataByteString = $attestationObject['authData']->get_byte_string(); $authDataByteArray = array_values(unpack('C*', $authDataByteString)); $rpIdHash = array_slice($authDataByteArray, 0, 32); $flag = str_pad(decbin($authDataByteArray[32]), 8, 0, STR_PAD_LEFT); $signCount = $this->byteArrayToEndian(array_slice($authDataByteArray, 33, 4));
  81. 8. 伴ݕূ༻ͷΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ઌ΄Ͳొ࿥ϦΫΤετͨ͠Ϣʔβʔ͔Ͳ͏͔ΛνΣοΫ // check RP ID hash if

    ($this->byteArrayToHex($rpIdHash) != hash('sha256', config('webauthn.rp.id'))) { throw new \Exception('Invalid! Not match RP ID Hash'); } // check challenge $clientChallenge = base64_decode( str_replace('-', '+', str_replace('_', ‘/', $clientDataJSON->challenge))); if ($clientChallenge != $challenge) { throw new \Exception('Invalid! Not match Challenge'); } // check type if ($clientDataJSON->type != 'webauthn.create') { throw new \Exception('Invalid! Type is not "webauthn.create"'); }
  82. 8. 伴ݕূ༻ͷΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php ެ։伴ΛΰϦͬͱ࡞੒ Ϣʔβʔʹඥ͚ͮͯอଘ // attestedCredentialData ͷύʔεʢ؆қ൛ʣ if (substr($flag,

    1, 1)) { $aaguid = array_slice($authDataByteArray, 37, 16); $credentialIdLength = array_slice($authDataByteArray, 53, 2); $credentialIdLength = $this->byteArrayToEndian($credentialIdLength); $credentialId = array_slice($authDataByteArray, 55, $credentialIdLength); $credentialPublicKey = $this->byteArrayToString(array_slice($authDataByteArray, 55 + $credentialIdLength)); $credentialPublicKeyData = CBOREncoder::decode($credentialPublicKey); if ($this->byteArrayToHex($credentialId) !== bin2hex(base64_decode($publicKeyCredential->rawId))) { throw new \Exception('invalid! Not match Credential ID'); } } else { throw new \Exception('Invalid! AttestedCredentialData is not Include.'); } // ެ։伴ͷௐ੔ $key1 = unpack('C*', $credentialPublicKeyData['-2']->get_byte_string()); $key2 = unpack('C*', $credentialPublicKeyData['-3']->get_byte_string()); $credentialPublicKey = array_merge([4], $key1, $key2); $credentialPublicKey = $this->createPubkeyPem($credentialPublicKey);
  83. 9. ॺ໊ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ • جຊతʹొ࿥࣌ͱಉ͜͡ͱΛ͢ΔͷͰৄࡉ͸ׂѪ • ϝʔϧΞυϨεͰϢʔβʔΛߜΓࠐΈɺ • Ϣʔβʔʹඥ͍͍ͮͯΔ伴ͷIDΛ౉͢ඞཁ͕͋Δ app/Http/Controllers/Auth/LoginController.php

  84. 10. ॺ໊ݕূ༻ͷΞΫγϣϯΛ௥Ճ • جຊతʹొ࿥࣌ͱಉ͜͡ͱΛ͢ΔͷͰৄࡉ͸ׂѪ • ॺ໊͕ૹΒΕͯ͘ΔͷͰɺอଘͯ͋͠Δެ։伴Ͱݕূ • ݕূ͕௨ͬͨΒϩάΠϯॲཧΛ࣮ߦ app/Http/Controllers/Auth/LoginController.php

  85. ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ ✅

    WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ WebAuthn Laravel σϞ ɾ ·ͱΊ
  86. WebAuthn -BSBWFMσϞ

  87. σϞ͸ແବʹ Lambda___ Ͱಈ͔ͯ͠·͢ ͦͬͪͷ࿩Λฉ͖͍ͨํ͸ Ask the Speaker Ͱ

  88. ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ ✅

    WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ ✅ WebAuthn Laravel σϞ ·ͱΊ
  89. ·ͱΊ • WebAuthn Λར༻͢Δ͜ͱͰɺύεϫʔυೝূͷऑ఺ Λࠀ෰͢Δ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨɻ • PHPͰ΋RPαʔόʔΛߏங͢Δ͜ͱ͸Մೳɻɹɹɹɹ ͨͩɺ͍͍ײ͡ʹڊਓͷݞʹ৐͔ͬΓ͍ͨɻ • ݱ࣌఺Ͱ͸ରԠ͍ͯ͠ͳ͍ϒϥ΢β΋݁ߏ͋ΔͷͰɺ

    WebAuthn 1ຊͰαʔϏεΛӡ༻͢Δͷ͸೉ͦ͠͏ɻ • ΞΧ΢ϯτϦΧόϦͷํ๏Λݕ౼͠ͳ͍ͱ͍͚ͳ͍ɻ
  90. ࢀߟจݙ [3] WebAuthn͜ͱ͸͡Ί https://tech.mercari.com/entry/2019/06/04/120000 [4] ύεϫʔυϨεΛࢧ͑Δٕज़! ݕূ! ࣍ੈ୅Webೝূ ~WebAuthnೖ໳ɾPHP࣮૷ฤ~ https://recruit.gmo.jp/engineer/jisedai/blog/webauthn/

    [5] ηΩϡϦςΟാͰ͔ͭ·͑ͯ https://booth.pm/ja/items/1317173 ຊεϥΠυͷ࡞੒ʹ͋ͨΓɺ ԼهͷαΠτٴͼॻ੶Λࢀߟʹ͍͖ͤͯͨͩ͞·ͨ͠ɻ [2] Web Authentication API https://developer.mozilla.org/ja/docs/Web/API/Web_Authentication_API [1] Web Authentication: An API for accessing Public Key Credentials Level 1 https://www.w3.org/TR/webauthn/
  91. We are hiring!! https://fusic.github.io גࣜձࣾ Fusic Ͱ͸ɺ ςΫϊϩδʔ͕େ޷͖ͳΤϯδχΞΛืू͍ͯ͠·͢ɻ ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠