Slide 1

Slide 1 text

Password-less Web applications created with WebAuthn. WebAuthn Ͱ࡞ΔύεϫʔυϨεWEBΞϓϦέʔγϣϯ 2019/06/29 PHP Conference Fukuoka 2019 Fusic Co., Ltd Kensuke Masatani (@k_masatany)

Slide 2

Slide 2 text

ࣗݾ঺հ • ੓୩ ݡ༞ (@k_masatany) • גࣜձࣾ Fusic ॴଐ • ݩ૊ΈࠐΈܥΤϯδχΞ • ࠓ͸ Laravel ϝΠϯͷ PHPer • AWS ΋ಘҙʢͰ΋͍ͭઌ೔ೝఆ੾ΕͪΌ͍·ͨ͠ʣ • ࠷ۙ͸αʔόʔϨεͳ Laravel Λಈ͔ͯ͠༡ΜͰ͍Δ

Slide 3

Slide 3 text

ΞδΣϯμ ✅ ࣗݾ঺հ WebAuthn ͱ͸ ɾ WebAuthn ͷ۩ମతͳೝূಈ࡞ ɾ WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ

Slide 4

Slide 4 text

WebAuthn ͱ͸

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

WebAuthn ϒϥ΢βରԠঢ়گʢ2019/06/28࣌఺ʣ https://caniuse.com/#feat=webauthn

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

ύεϫʔυೝূͷԿ͕໰୊͔

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

ύεϫʔυೝূͷ՝୊ • ೖྗ΋؅ཧ΋໘౗ • ໘౗Ώ͑ʹ੬ऑͳύεϫʔυΛར༻ • ໘౗Ώ͑ʹైḤͳ؅ཧ͕͞Εͯ͠·͏ ɹ ɹͦ΋ͦ΋ɺ ɹύεϫʔυͱ͍͏໊ͷൿಗ৘ใ͕ ɹΠϯλʔωοτ্ΛྲྀΕ͍ͯΔ͜ͱ͕໰୊

Slide 22

Slide 22 text

WebAuthn ͰͲ͏มΘΔ͔

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

͍͍͜ͱ͹͔ΓͰ͸ͳ͍

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ WebAuthn ͷ۩ମతͳೝূಈ࡞ ɾ WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ

Slide 37

Slide 37 text

WebAuthn ͷ۩ମతͳೝূಈ࡞

Slide 38

Slide 38 text

WebAuthn ͷ 3େཁૉ ໊শ ໾ׂ $MJFOU ʢΫϥΠΞϯτʣ 8FC"VUIOΛ࣮ߦ͢Δϒϥ΢β 8FC"VUIOͷ"1*ʹରԠ͍ͯ͠Δඞཁ͕͋Δ "VUIFOUJDBUPS ʢೝূثʣ ࣮ࡍʹຊਓͷ֬ೝͱΩʔϖΞͷੜ੒Λߦ͏ ֎෦ೝূثʢ64#Ωʔɺ:VCJLFZͳͲʣ ಺෦ೝূثʢεϚϗ΍.BDͷࢦ໲ೝূͳͲʣ 3FMZJOH1BSUZ ʢ31ʣ ࣮ࡍʹϢʔβʔͷొ࿥΍؅ཧΛߦ͏αΠτ ೝূث͔Βૹ৴͞ΕΔެ։伴Λอଘ

Slide 39

Slide 39 text

Ϣʔβʔొ࿥࣌ ʢUser Registrationʣ

Slide 40

Slide 40 text

Client Authenticator RP

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Client KeyPair ᶇ Create KeyPair ᶉ Send AD ᶆ Verify User ᶃ Request Challenge ᶄ Response Challenge ᶊ Verify AD ᶈ Response AD ᶅ Request KeyPair Authenticator Data Authenticator RP ᶋ Create User ొ࿥׬ྃ

Slide 51

Slide 51 text

Ϣʔβʔೝূ࣌ ʢUser Authenticationʣ

Slide 52

Slide 52 text

Client Authenticator RP

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

Client ᶆ Verify User ᶃ Request Challenge & KeyID Authenticator RP ᶄ Response Challenge ᶅ Request Signature ೝূث͕Ϣʔβʔͷ֬ೝΛ࣮ߦ

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

ॺ໊ΛRP΁ Client Signeture ᶇ Create Signature ᶉ Send AD ᶆ Verify User ᶃ Request Challenge & KeyID ᶈ Response AD Authenticator Data Authenticator RP ᶄ Response Challenge ᶅ Request Signature

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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 ϩάΠϯ੒ޭ

Slide 62

Slide 62 text

ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ ɾ WebAuthn Laravel σϞ ɾ ·ͱΊ

Slide 63

Slide 63 text

WebAuthn Λ -BSBWFMʹ૊ΈࠐΜͰΈΔ

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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(); }); }

Slide 68

Slide 68 text

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. 伴อଘ༻ͷςʔϒϧΛ࡞੒

Slide 69

Slide 69 text

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');

Slide 70

Slide 70 text

5. view ϑΝΠϧͷฤू & ௥Ճ ɾresources/views/auth/register.blade.php ɾresources/views/auth/login.blade.php ɾ΄΅σϑΥϧτͷ··࢖༻ ɾύεϫʔυΛೖྗ͢ΔϑΥʔϜΛ࡟আ ɾPOST ઌΛɺઌ΄Ͳ࡞੒ͨ͠ *-confirm ΞΫγϣϯʹมߋ

Slide 71

Slide 71 text

6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ https://github.com/web-auth/webauthn-lib ࠓճ͸ web-auth/webauthn-lib Λར༻ͯ͠࡞੒͠·͢

Slide 72

Slide 72 text

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 );

Slide 73

Slide 73 text

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 );

Slide 74

Slide 74 text

6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php νϟϨϯδΛੜ੒ // Challenge $challenge = random_bytes(32); session(['register.challenge' => base64_encode($challenge)]); ɾϥϯμϜͳόΠτྻ ɾޙ΄Ͳݕূ͢ΔͷͰɺηογϣϯ౳ʹอ࣋

Slide 75

Slide 75 text

6. 伴ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ app/Http/Controllers/Auth/RegisterController.php 伴ੜ੒ͷύϥϝʔλΛઃఆ // Public Key Credential Parameters $publicKeyCredentialParametersList = [ new PublicKeyCredentialParameters( ‘public-key', Algorithms::COSE_ALGORITHM_ES256 ), ]; ɾެ։伴ೝূํࣜ ɾES256ͱ͍͏ΞϧΰϦζϜͷΈڐՄ ɾWindows Hello Λ࢖͍͍ͨͳΒ RS256 ΋ڐՄ

Slide 76

Slide 76 text

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));

Slide 77

Slide 77 text

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'));

Slide 78

Slide 78 text

7. 伴Λੜ੒͢ΔͨΊͷεΫϦϓτΛviewʹ௥Ճ resources/views/auth/login-confirm.blade.php αʔόʔͰੜ੒ͨ͠σʔλΛ js ଆͰ࢖͏ͨΊʹௐ੔ 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 Λࢀߟʹ࣮૷

Slide 79

Slide 79 text

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'; });

Slide 80

Slide 80 text

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));

Slide 81

Slide 81 text

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"'); }

Slide 82

Slide 82 text

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);

Slide 83

Slide 83 text

9. ॺ໊ੜ੒༻ͷϨεϙϯεΛฦ͢ΞΫγϣϯΛ௥Ճ • جຊతʹొ࿥࣌ͱಉ͜͡ͱΛ͢ΔͷͰৄࡉ͸ׂѪ • ϝʔϧΞυϨεͰϢʔβʔΛߜΓࠐΈɺ • Ϣʔβʔʹඥ͍͍ͮͯΔ伴ͷIDΛ౉͢ඞཁ͕͋Δ app/Http/Controllers/Auth/LoginController.php

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ ✅ WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ WebAuthn Laravel σϞ ɾ ·ͱΊ

Slide 86

Slide 86 text

WebAuthn -BSBWFMσϞ

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

ΞδΣϯμ ✅ ࣗݾ঺հ ✅ WebAuthn ͱ͸ ✅ WebAuthn ͷ۩ମతͳೝূಈ࡞ ✅ WebAuthn Λ Laravel ʹ૊ΈࠐΜͰΈΔ ✅ WebAuthn Laravel σϞ ·ͱΊ

Slide 89

Slide 89 text

·ͱΊ • WebAuthn Λར༻͢Δ͜ͱͰɺύεϫʔυೝূͷऑ఺ Λࠀ෰͢Δ͜ͱ͕Ͱ͖ΔΑ͏ʹͳͬͨɻ • PHPͰ΋RPαʔόʔΛߏங͢Δ͜ͱ͸Մೳɻɹɹɹɹ ͨͩɺ͍͍ײ͡ʹڊਓͷݞʹ৐͔ͬΓ͍ͨɻ • ݱ࣌఺Ͱ͸ରԠ͍ͯ͠ͳ͍ϒϥ΢β΋݁ߏ͋ΔͷͰɺ WebAuthn 1ຊͰαʔϏεΛӡ༻͢Δͷ͸೉ͦ͠͏ɻ • ΞΧ΢ϯτϦΧόϦͷํ๏Λݕ౼͠ͳ͍ͱ͍͚ͳ͍ɻ

Slide 90

Slide 90 text

ࢀߟจݙ [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/

Slide 91

Slide 91 text

We are hiring!! https://fusic.github.io גࣜձࣾ Fusic Ͱ͸ɺ ςΫϊϩδʔ͕େ޷͖ͳΤϯδχΞΛืू͍ͯ͠·͢ɻ ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠