Google์ ๋ก๊ทธ์ธํ ๋ ๋น๋ฐ๋ฒํธ ๋์ ์ง๋ฌธ์ ์ฐ๋ ๊ฒฝํ์ ํด๋ณธ ์ ์ด ์์ ๊ฒ๋๋ค. ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํ์ง๋ ์์๋๋ฐ ๋ก๊ทธ์ธ์ด ๋ฉ๋๋ค. ์ด๊ฒ passkey์ ๋๋ค.
๊ฒ์ผ๋ก๋ ๋จ์ํด ๋ณด์ด์ง๋ง, ๊ทธ ์์์๋ ๊ณต๊ฐ ํค ์ํธํ, origin ๊ฒ์ฆ, ํ๋์จ์ด ๋ณด์ ์์ญ์ด ์กฐํฉ๋ ์ธ์ฆ ํ๋ฆ์ด ๋์ํฉ๋๋ค. ์ด ๊ธ์์๋ ๊ทธ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ํ์ด๋ด ๋๋ค.
์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋์ฒดํ๋ ค๋ ๊ฑธ๊น์? ๋ถํธํด์๊ฐ ์๋๋๋ค. ๊ตฌ์กฐ๊ฐ ๊ทผ๋ณธ์ ์ผ๋ก ์ทจ์ฝํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋น๋ฐ๋ฒํธ๋ ๊ณต์ ๋น๋ฐ(shared secret)์ ๋๋ค. "์๋ฒ์ ๋ด๊ฐ ๊ฐ์ ๋น๋ฐ์ ์๊ณ ์๋ค"๋ ์ฌ์ค๋ก ๋ณธ์ธ์ ์ฆ๋ช ํฉ๋๋ค. ์๋ฌผ์ ์ ๋น๋ฐ๋ฒํธ๋ฅผ ์๋ฒ๋ ์๊ณ ๋๋ ์๋ ๊ตฌ์กฐ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
์ด ๊ตฌ์กฐ์์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ ์ง์ ์ ๋ ๊ตฐ๋ฐ์ ๋๋ค.
์๋ฒ๊ฐ ํธ๋ฆฌ๋ฉด? ๋น๋ฐ๋ฒํธ ํด์๊ฐ ์ ์ถ๋ฉ๋๋ค. ์คํ๋ผ์ธ์์ ํฌ๋ํนํ ์ ์์ต๋๋ค.
ํผ์ฑ ์ฌ์ดํธ์ ์ ๋ ฅํ๋ฉด? ๋น๋ฐ๋ฒํธ๋ "๊ฐ"์ด๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๊ฐ ๊ฐ์ง ์ฌ์ดํธ์ ์ ๋ ฅํ๋ฉด ๊ทธ๋๋ก ๊ณต๊ฒฉ์์๊ฒ ์ ๋ฌ๋ฉ๋๋ค. OTP๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์ง์ ์ฝ๊ณ ํ์ดํํ๋ ๊ตฌ์กฐ์ธ ์ด์, ์ค์๊ฐ์ผ๋ก ์ค๊ณํ๋ฉด ๋ซ๋ฆฝ๋๋ค.
Passkey๋ ์ด ๋ ๋ฌธ์ ๋ฅผ ๋์์ ํด๊ฒฐํฉ๋๋ค.
Passkey์ ์๋ฆฌ๋ฅผ ํ ๋ฌธ์ฅ์ผ๋ก ์์ฝํ๋ฉด ์ด๋ ์ต๋๋ค.
์๋ฒ์๋ ์๋ฌผ์ (๊ณต๊ฐ ํค)๋ฅผ ์ฃผ๊ณ , ์ด์ (๊ฐ์ธ ํค)๋ ๋ด ๊ธฐ๊ธฐ์๋ง ๋ณด๊ดํ๋ค.
๋น๋ฐ๋ฒํธ ๋ฐฉ์์ ์๋ฒ์ ๋ด๊ฐ ๊ฐ์ ์ด์ ๋ฅผ ๊ณต์ ํ๋ ๊ตฌ์กฐ์ ๋๋ค. Passkey๋ ์์ ๋ค๋ฆ ๋๋ค. ์๋ฒ๊ฐ ๊ฐ์ง ๊ฑด ์๋ฌผ์ ๋ฟ์ด๋ผ, ์๋ฒ๊ฐ ํดํน๋นํด๋ ์ด์ ๋ ์์ ํฉ๋๋ค.
์ธ์ฆํ ๋๋ ์๋ฒ๊ฐ "์ด ์์๋ฅผ ์ด์ด๋ด"(์ฑ๋ฆฐ์ง)๋ผ๊ณ ๋ณด๋ด๋ฉด, ๋ด ๊ธฐ๊ธฐ๊ฐ ์ด์ ๋ก ์ด์ด์ ์ฆ๊ฑฐ๋ฅผ ๋๋ ค๋ณด๋ ๋๋ค. ์๋ฒ๋ ์๋ฌผ์ ๋ก "๋ง๋ ์ด์ ๋ก ์ด์๋์ง" ํ์ธ๋ง ํฉ๋๋ค.
์ด๊ฒ ๊ณต๊ฐ ํค ์ํธํ(public key cryptography)์ ํต์ฌ์ด๊ณ , Passkey๋ ์ด๊ฑธ ์น ์ธ์ฆ์ ์ ์ฉํ ๊ฒ์ ๋๋ค.
์ด ์ธ์ฆ ๊ตฌ์กฐ๋ฅผ ์คํํ๋ ๊ธฐ์ ํ์ค์ด FIDO2์ ๋๋ค. FIDO2๋ ๋ ๊ฐ์ ํ์ค์ด ํฉ์ณ์ง ์ด๋ฆ์ ๋๋ค.
WebAuthn (W3C): ์น ๊ฐ๋ฐ์๊ฐ ์ค์ ๋ก ์ฌ์ฉํ๋ JavaScript API์
๋๋ค. navigator.credentials.create()๋ก ํค ์์ ๋ง๋ค๊ณ , navigator.credentials.get()์ผ๋ก ์ธ์ฆํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์ ์๋ฒ ์ฌ์ด์ ํต์ ์ ๋ด๋นํฉ๋๋ค.
CTAP2 (FIDO Alliance): ๋ธ๋ผ์ฐ์ ์ ์ธ๋ถ ์ธ์ฆ๊ธฐ(YubiKey ๊ฐ์ ํ๋์จ์ด ๋ณด์ ํค) ์ฌ์ด์ ํต์ ํ๋กํ ์ฝ์ ๋๋ค. USB, NFC, Bluetooth๋ก ํต์ ํฉ๋๋ค.
์๋ฒ(Relying Party) ๋ธ๋ผ์ฐ์ ์ธ์ฆ๊ธฐ
โ โ โ
โโโโโโ WebAuthn API โโโโโบโ โ
โ (์น ๊ฐ๋ฐ์๊ฐ โโโโโโ CTAP2 โโโโโบโ ์ธ๋ถ: YubiKey ๋ฑ
โ ๋ค๋ฃจ๋ ์์ญ) โ โ (USB/NFC/BLE)
โ โ โ
โ โโโโ OS ๋ด๋ถ API โโโบโ ๋ด์ฅ: Touch ID,
โ โ (CTAP2 ์ ๊ฑฐ์นจ) โ Windows Hello ๋ฑ
ํต์ฌ์ ์ด๊ฒ๋๋ค. ์น ๊ฐ๋ฐ์๊ฐ ์ง์ ๋ค๋ฃจ๋ ๊ฑด WebAuthn API๋ฟ์ ๋๋ค. CTAP2๋ ๋ธ๋ผ์ฐ์ ์ OS๊ฐ ์์์ ์ฒ๋ฆฌํฉ๋๋ค. Touch ID๋ Windows Hello ๊ฐ์ ๋ด์ฅ ์ธ์ฆ๊ธฐ๋ CTAP2๋ ๊ฑฐ์น์ง ์๊ณ OS๊ฐ ์ง์ ํต์ ํฉ๋๋ค.
์๋ฒ(WebAuthn ์คํ์์๋ Relying Party, ์ค์ฌ์ RP๋ผ๊ณ ๋ถ๋ฆ ๋๋ค)๋ ์ฑ๋ฆฐ์ง๋ฅผ ์์ฑํ๊ณ , ๋์์จ ์๋ช ์ ๊ฒ์ฆํ๋ ์ญํ ๋ง ํฉ๋๋ค.
WebAuthn์๋ ๋ ๊ฐ์ง ํ๋ฆ์ด ์์ต๋๋ค. ๋ฑ๋ก(Registration)๊ณผ ์ธ์ฆ(Authentication)์ ๋๋ค. ์คํ์์๋ ์ด ํ๋ฆ์ "ceremony"๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
๋จผ์ ๋ฑ๋ก์ ๋๋ค. ์ฌ์ฉ์๊ฐ ์๋น์ค์ passkey๋ฅผ ์ฒ์ ์ค์ ํ๋ ๊ณผ์ ์ ๋๋ค.
1. ์๋ฒ๊ฐ "์ด ๋๋ค ๊ฐ์ ์๋ช
ํด๋ด" (challenge)๋ฅผ ๋ณด๋
2. ๋ธ๋ผ์ฐ์ ๊ฐ ์ธ์ฆ๊ธฐ์๊ฒ ์ ๋ฌ
3. ์ธ์ฆ๊ธฐ๊ฐ ์ ํค ์์ ์์ฑ โ ๊ฐ์ธ ํค๋ ๊ธฐ๊ธฐ์ ์ ์ฅ
4. ๊ณต๊ฐ ํค + ์๋ช
์ ์๋ฒ์ ์ ๋ฌ
5. ์๋ฒ๊ฐ ๊ณต๊ฐ ํค๋ฅผ ์ฌ์ฉ์ ๊ณ์ ์ ์ ์ฅ
์ฝ๋๋ก ๋ณด๋ฉด ์ด๋ ์ต๋๋ค.
// ์๋ฒ๊ฐ ๋ง๋๋ ๋ฑ๋ก ์ต์
const options: PublicKeyCredentialCreationOptions = {
// ๋๋ค ์ฑ๋ฆฐ์ง. ๋งค๋ฒ ์๋ก ์์ฑํด์ผ ํฉ๋๋ค.
// ์ด์ ์ ์ด ๊ฐ์ ์ฌ์ฌ์ฉํ๋ฉด ์ฌ์ ์ก ๊ณต๊ฒฉ(replay attack)์ ์ทจ์ฝํฉ๋๋ค.
challenge: crypto.getRandomValues(new Uint8Array(32)),
// Relying Party ์ ๋ณด.
// id๋ ๋๋ฉ์ธ ์ด๋ฆ์ด๊ณ , ๋ฑ๋ก ์ดํ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
// ์ด ๊ฐ์ด ํผ์ฑ ๋ฐฉ์ด์ ํต์ฌ์
๋๋ค (๋ค์์ ์์ธํ ๋ค๋ฃน๋๋ค).
rp: {
id: 'example.com',
name: 'Example Service',
},
// ์ฌ์ฉ์ ์ ๋ณด.
// id๋ ๋ด๋ถ ์๋ณ์๋ก, ์ด๋ฉ์ผ ๊ฐ์ ๊ฐ์ธ์ ๋ณด๋ฅผ ๋ฃ์ผ๋ฉด ์ ๋ฉ๋๋ค.
// ์ธ์ฆ๊ธฐ์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์
๋๋ค.
user: {
id: new Uint8Array(16),
name: 'user@example.com',
displayName: 'User',
},
// ํ์ฉํ ์ํธํ ์๊ณ ๋ฆฌ์ฆ.
// -7์ ES256 (ํ์๊ณก์ ), -257์ RS256 (RSA).
// ES256์ด ๊ฐ์ฅ ๋๋ฆฌ ์ฐ์ด๊ณ , ์๋ช
ํฌ๊ธฐ๋ ์์ต๋๋ค.
pubKeyCredParams: [
{ alg: -7, type: 'public-key' },
{ alg: -257, type: 'public-key' },
],
// ์ธ์ฆ๊ธฐ ์๊ตฌ์ฌํญ.
authenticatorSelection: {
// 'required': ์ธ์ฆ๊ธฐ๊ฐ ํค๋ฅผ ์์ฒด ์ ์ฅํด์ผ ํจ (passkey์ ํ์ ์กฐ๊ฑด)
residentKey: 'required',
// 'preferred': ๊ฐ๋ฅํ๋ฉด ์์ฒด์ธ์/PIN์ผ๋ก ๋ณธ์ธ ํ์ธ
userVerification: 'preferred',
},
timeout: 60000,
};
// ๋ธ๋ผ์ฐ์ ์์ ์คํ. ์ด ์์ ์ ์์ฒด์ธ์ ํ๋กฌํํธ๊ฐ ๋น๋๋ค.
const credential = await navigator.credentials.create({
publicKey: options,
});
// ์๋ต์๋ ๋ ๊ฐ์ง๊ฐ ๋ค์ด์์ต๋๋ค:
// - clientDataJSON: ๋ธ๋ผ์ฐ์ ๊ฐ ๋ง๋ ๋ฉํ๋ฐ์ดํฐ (origin, challenge ๋ฑ)
// - attestationObject: ์ธ์ฆ๊ธฐ๊ฐ ๋ง๋ ๊ณต๊ฐ ํค์ credential ID
// ์๋ฒ์์ ๊ฒ์ฆํ ๊ฒ๋ค:
// 1. clientDataJSON์ origin์ด ์ฐ๋ฆฌ ๋๋ฉ์ธ์ธ์ง (ํผ์ฑ ๋ฐฉ์ด)
// 2. challenge๊ฐ ์ฐ๋ฆฌ๊ฐ ๋ฐ๊ธํ ๊ฒ๊ณผ ๊ฐ์์ง (์ฌ์ ์ก ๋ฐฉ์ด)
// 3. attestationObject์์ ๊ณต๊ฐ ํค๋ฅผ ๊บผ๋ด์ ์ฌ์ฉ์ ๊ณ์ ์ ์ ์ฅ
์ฌ๊ธฐ์ rp.id๊ฐ ์ ์ค์ํ์ง ์ง๊ณ ๋์ด๊ฐ๋๋ค. example.com์ผ๋ก ๋ฑ๋ก๋ passkey๋ evil-example.com์์ ์ ๋ ๋์ํ์ง ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฌ ํ์ด์ง์ ๋๋ฉ์ธ๊ณผ rp.id๋ฅผ ๋น๊ตํด์, ๋ค๋ฅด๋ฉด ์ธ์ฆ๊ธฐ์ ์์ ์์ฒญ์ ๋ณด๋ด์ง ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ URL์ ๊ผผ๊ผผํ ํ์ธํ ํ์๊ฐ ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ๊ฐ ๋์ ํด์ค๋๋ค.
๋ฑ๋ก์ด ๋๋๋ฉด, ์ดํ ๋ก๊ทธ์ธ์ ์ธ์ฆ ํ๋ฆ์ ํ๋๋ค.
1. ์๋ฒ๊ฐ ์ challenge๋ฅผ ๋ณด๋
2. ์ธ์ฆ๊ธฐ๊ฐ ์ ์ฅ๋ ๊ฐ์ธ ํค๋ก challenge์ ์๋ช
3. ์๋ช
์ ์๋ฒ์ ์ ๋ฌ
4. ์๋ฒ๊ฐ ๋ฑ๋ก ๋ ์ ์ฅํ ๊ณต๊ฐ ํค๋ก ์๋ช
์ ๊ฒ์ฆ
// ์๋ฒ๊ฐ ๋ง๋๋ ์ธ์ฆ ์ต์
const options: PublicKeyCredentialRequestOptions = {
challenge: crypto.getRandomValues(new Uint8Array(32)),
rpId: 'example.com',
// allowCredentials๋ฅผ ๋น์๋๋ฉด ์ธ์ฆ๊ธฐ๊ฐ ์์์
// ์ด ๋๋ฉ์ธ์ ๋ง๋ passkey๋ฅผ ์ฐพ์์ ๋ณด์ฌ์ค๋๋ค.
// ์ฌ์ฉ์๊ฐ ์ด๋ฉ์ผ์ ๋จผ์ ์
๋ ฅํ ํ์๊ฐ ์์ต๋๋ค.
allowCredentials: [],
userVerification: 'preferred',
timeout: 60000,
};
const assertion = await navigator.credentials.get({
publicKey: options,
});
// ์๋ต ๊ตฌ์กฐ:
// - clientDataJSON: origin, challenge (๋ธ๋ผ์ฐ์ ๊ฐ ์ฑ์)
// - authenticatorData: ๋๋ฉ์ธ ํด์, ์ฌ์ฉ์ ํ์ธ ์ฌ๋ถ, ์๋ช
์นด์ดํฐ
// - signature: ์ ๋ ๊ฐ์ ๊ฐ์ธ ํค๋ก ์๋ช
ํ ๊ฒฐ๊ณผ
// - userHandle: ๋ฑ๋ก ๋ ์ค์ ํ user.id (์ด๊ฑธ๋ก ๋๊ตฌ์ธ์ง ์๋ณ)
์๋ฒ ๊ฒ์ฆ ๊ณผ์ ์ ํ์ด๋ณด๋ฉด ์ด๋ ์ต๋๋ค.
// ์๋ฒ๊ฐ ํ์ธํ๋ ๊ฒ๋ค:
// 1. origin ํ์ธ: clientDataJSON์ origin์ด 'https://example.com'์ธ์ง
// โ ๋ค๋ฅธ ๋๋ฉ์ธ์์ ์จ ์์ฒญ์ด๋ฉด ๊ฑฐ๋ถ
// 2. challenge ํ์ธ: ์ฐ๋ฆฌ๊ฐ ๋ฐฉ๊ธ ๋ฐ๊ธํ challenge์ ๊ฐ์์ง
// โ ์ด์ ์์ฒญ์ ๋ณต์ฌํด์ ๋ณด๋ด๋ ์ฌ์ ์ก ๊ณต๊ฒฉ ์ฐจ๋จ
// 3. ์๋ช
๊ฒ์ฆ: ๋ฑ๋ก ๋ ์ ์ฅํ ๊ณต๊ฐ ํค๋ก signature๊ฐ ์ ํจํ์ง ํ์ธ
// ๊ฒ์ฆ ๋์ = authenticatorData + SHA-256(clientDataJSON)
// โ ์ด ๋ฐ์ดํฐ๊ฐ ์กฐ๊ธ์ด๋ผ๋ ๋ณ์กฐ๋์์ผ๋ฉด ์๋ช
์ด ๊นจ์ง
// 4. ์ฌ์ฉ์ ์๋ณ: userHandle ๊ฐ์ผ๋ก ์ด๋ค ๊ณ์ ์ธ์ง ํ์ธ
// 5. signCount ํ์ธ: ์ด์ ๋ก๊ทธ์ธ ๋๋ณด๋ค ํฐ ๊ฐ์ธ์ง
// โ ์ธ์ฆ๊ธฐ๊ฐ ๋ณต์ ๋์๋์ง ํ์ง (๋ค์์ ์์ธํ)
์๋ช
๊ฒ์ฆ ๋์์ด authenticatorData + SHA-256(clientDataJSON)์ด๋ผ๋ ์ ์ด ์ค์ํฉ๋๋ค. clientDataJSON์๋ origin๊ณผ challenge๊ฐ ๋ค์ด์๊ณ , ์ด๊ฑธ ํด์ฑํ ๊ฐ์ด ์๋ช
์ ํฌํจ๋๋ฏ๋ก, origin์ด๋ challenge๊ฐ ํ ๋นํธ๋ผ๋ ๋ฐ๋๋ฉด ์๋ช
๊ฒ์ฆ์ด ์คํจํฉ๋๋ค. ์ค๊ฐ์์ ๊ฐ์ ๋ฐ๊พธ๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ ๊ตฌ์กฐ์
๋๋ค.
์ฌ๊ธฐ๊น์ง๊ฐ WebAuthn์ ์๋ ์ค๊ณ์ ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ด ์ค๊ณ์๋ ์ค์ฉ์ ์ธ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
๊ฐ์ธ ํค๊ฐ ํ๋์จ์ด ์ธ์ฆ๊ธฐ(YubiKey ๋ฑ) ์์ ๊ฐํ ์์ผ๋, ๊ธฐ๊ธฐ๋ฅผ ์์ด๋ฒ๋ฆฌ๋ฉด ํค๋ ๊ฐ์ด ์ฌ๋ผ์ง๋๋ค. ๋ณด์์ ์ผ๋ก๋ ์ด์์ ์ด์ง๋ง, ์ผ๋ฐ ์ฌ์ฉ์์๊ฒ "YubiKey๋ฅผ ํญ์ ๋ค๊ณ ๋ค๋์ธ์"๋ผ๊ณ ํ ์๋ ์์์ต๋๋ค.
Passkey๋ ์ด ๋ฌธ์ ๋ฅผ ๊ฐ์ธ ํค์ ํด๋ผ์ฐ๋ ๋๊ธฐํ๋ก ํด๊ฒฐํฉ๋๋ค. "Passkey"๋ผ๋ ๋จ์ด๋ ๊ธฐ์ ํ์ค ์ด๋ฆ์ด ์๋๋ผ, Apple/Google/Microsoft๊ฐ ๋ง๋ ๋ง์ผํ ์ฉ์ด์ ๋๋ค. ๊ธฐ์ ์ ์ผ๋ก๋ "๋๊ธฐํ๋๋ WebAuthn discoverable credential"์ ๋๋ค.
| Device-bound (๊ธฐ๊ธฐ ๊ท์) | Synced Passkey (๋๊ธฐํ) | |
|---|---|---|
| ๊ฐ์ธ ํค ์์น | ๊ธฐ๊ธฐ์ ๋ณด์ ์นฉ ์. ์ ๋ ๋ฐ์ผ๋ก ์ ๋๊ฐ | ํด๋ผ์ฐ๋์ E2E ์ํธํ๋ก ์ ์ฅ, ๊ธฐ๊ธฐ ๊ฐ ๋๊ธฐํ |
| ๊ธฐ๊ธฐ๋ฅผ ์์ผ๋ฉด | ํค๋ ์ฌ๋ผ์ง. ๋ฐฑ์ ์๋จ ํ์ | ๋ค๋ฅธ ๊ธฐ๊ธฐ์์ ์๋ ๋ณต์ |
| ์ด๋์ ์ธ ์ ์๋ | ๋ฑ๋กํ ๊ธฐ๊ธฐ์์๋ง | ๊ฐ์ ์ํ๊ณ(Apple/Google/MS)์ ๋ชจ๋ ๊ธฐ๊ธฐ |
| ๋ณด์ ์์ค | ์ต๊ณ (๋ฌผ๋ฆฌ์ ์์ ์ฆ๋ช ) | ๋์ (ํด๋ผ์ฐ๋ ๊ณ์ ๋ณด์์ ์์กด) |
| ์ ํฉํ ์ํฉ | ๊ธฐ์ ํ๊ฒฝ, ๊ณ ๋ณด์ ์์คํ | ์ผ๋ฐ ์๋น์ ์๋น์ค |
Apple: iCloud Keychain์ผ๋ก ๋๊ธฐํํฉ๋๋ค. iPhone์์ ๋ง๋ passkey๊ฐ Mac์์๋ ์ธ ์ ์๋ ์ด์ ์ ๋๋ค. ๊ฐ์ธ ํค๋ ๊ธฐ๊ธฐ์ Secure Enclave์์๋ง ๋ณตํธํ๋๊ณ , iCloud์๋ ์ํธํ๋ ์ํ๋ก๋ง ์กด์ฌํฉ๋๋ค.
Google: Google Password Manager๋ฅผ ํตํด Android ๊ธฐ๊ธฐ ๊ฐ, ๊ทธ๋ฆฌ๊ณ Chrome ๋ฐ์คํฌํฑ์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Microsoft: Windows Hello๋ฅผ ํตํด ๊ด๋ฆฌํ๋ฉฐ, Microsoft ๊ณ์ ์ ์ฐ๊ฒฐ๋ ๊ธฐ๊ธฐ ๊ฐ ๋๊ธฐํ๋ฅผ ์ง์ํฉ๋๋ค.
ํ ๊ฐ์ง ์ ์ฝ์ด ์์ต๋๋ค. Apple์์ ๋ง๋ passkey๋ Android๋ก ์๋ ๋๊ธฐํ๋์ง ์์ต๋๋ค. ์ํ๊ณ๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด FIDO Alliance๊ฐ ๋ ๊ฐ์ง ํ์ค์ ๋ง๋ค์์ต๋๋ค.
Apple์ด iOS 26(2025๋ 9์)์์ CXP๋ฅผ ์ต์ด ๊ตฌํํ์ฌ, iCloud Keychain์ passkey๋ฅผ Bitwarden ๊ฐ์ ์๋ํํฐ ์ฑ์ผ๋ก ๋ด๋ณด๋ผ ์ ์๊ฒ ๋์์ต๋๋ค.
๋น์ฅ ๋ค๋ฅธ ์ํ๊ณ ๊ธฐ๊ธฐ์์ passkey๋ฅผ ์จ์ผ ํ๋ค๋ฉด, Cross-Device Authentication์ ์ฌ์ฉํฉ๋๋ค.
1. PC ๋ธ๋ผ์ฐ์ ์์ ๋ก๊ทธ์ธ ์๋
2. "๋ค๋ฅธ ๊ธฐ๊ธฐ์ ํจ์คํค ์ฌ์ฉ" ์ ํ
3. QR ์ฝ๋๊ฐ ํ์๋จ
4. ์ค๋งํธํฐ์ผ๋ก QR ์ค์บ
5. ์ค๋งํธํฐ๊ณผ PC๊ฐ Bluetooth(BLE)๋ก ๊ฐ๊น์ด ์๋์ง ํ์ธ
6. ์ค๋งํธํฐ์์ ์์ฒด์ธ์
7. ์๋ช
์ด PC ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ์๋ฒ๋ก ์ ๋ฌ
5๋ฒ์ Bluetooth ๊ทผ์ ์ฑ ํ์ธ์ด ํต์ฌ์ ๋๋ค. QR ์ฝ๋๋ง์ผ๋ก๋ ์๊ฒฉ ๊ณต๊ฒฉ์๊ฐ ์คํฌ๋ฆฐ์ท์ ์ฐ์ด์ ์ ์ฉํ ์ ์์ง๋ง, Bluetooth ๋ฒ์(์ฝ 10m) ์์ ๋ฌผ๋ฆฌ์ ์ผ๋ก ์์ด์ผ ํ๋ฏ๋ก ์๊ฒฉ ํผ์ฑ์ด ์ฐจ๋จ๋ฉ๋๋ค.
๋น๋ฐ๋ฒํธ ๋ก๊ทธ์ธ์์๋ ์ด๋ฉ์ผ์ ๋จผ์ ์ ๋ ฅํด์ผ ํฉ๋๋ค. ์๋ฒ๊ฐ "์ด ์ฌ์ฉ์์ ๋น๋ฐ๋ฒํธ ํด์๊ฐ ๋ญ์์ง?" ํ๊ณ ์ฐพ์์ผ ํ๋๊น์.
์ด๊ธฐ WebAuthn์์๋ ๋น์ทํ์ต๋๋ค. ์๋ฒ๊ฐ allowCredentials์ "์ด credential ID๋ค ์ค ํ๋๋ฅผ ์จ๋ผ"๊ณ ๋ชฉ๋ก์ ๋๊ฒจ์ค์ผ ํ๊ณ , ๊ทธ๋ฌ๋ ค๋ฉด ๋จผ์ ๋๊ตฌ์ธ์ง ์์์ผ ํ์ต๋๋ค.
Discoverable Credential(๊ณผ๊ฑฐ์๋ Resident Key๋ผ๊ณ ๋ถ๋ ์ต๋๋ค)์ด ์ด ์ ์ฝ์ ์์ฑ๋๋ค. ์ธ์ฆ๊ธฐ๊ฐ credential ID์ user.id๋ฅผ ์์ฒด ์ ์ฅํ๋ฏ๋ก, ์๋ฒ๊ฐ ๋ชฉ๋ก์ ์ ๋๊ฒจ์ค๋ ์ธ์ฆ๊ธฐ๊ฐ "์ด ๋๋ฉ์ธ์ ๋ด๊ฐ ๊ฐ์ง ํค๊ฐ ์๋ค" ํ๊ณ ์์์ ์ฐพ์ต๋๋ค.
const options: PublicKeyCredentialRequestOptions = {
challenge: crypto.getRandomValues(new Uint8Array(32)),
rpId: 'example.com',
// ๋น ๋ฐฐ์ด = "๋ค๊ฐ ์์์ ์ฐพ์๋ด"
// ์ธ์ฆ๊ธฐ๊ฐ ์ด ๋๋ฉ์ธ์ ๋ฑ๋ก๋ passkey๋ฅผ ์์ฒด์ ์ผ๋ก ์ฐพ์์ ๋ณด์ฌ์ค
allowCredentials: [],
userVerification: 'required',
};
const assertion = await navigator.credentials.get({ publicKey: options });
// assertion.response.userHandle์ ๋ฑ๋ก ๋ ์ค์ ํ user.id๊ฐ ๋ด๊ฒจ์ด
// ์๋ฒ๋ ์ด ๊ฐ์ผ๋ก "์, ์ด ์ฌ์ฉ์๊ตฌ๋" ํ๊ณ ์๋ณ
๋ชจ๋ passkey๋ ์ ์์ discoverable credential์ ๋๋ค. Passkey๋ฅผ ์ง์ํ๋ค๋ฉด ์ด๋ฉ์ผ ์ ๋ ฅ ์๋ ๋ก๊ทธ์ธ์ด ์๋์ผ๋ก ๊ฐ๋ฅํฉ๋๋ค.
"passkey๋ก๋ง ๋ก๊ทธ์ธ"์ ๊ฐ์ ํ๋ฉด passkey๊ฐ ์๋ ์ฌ์ฉ์๋ ๋ก๊ทธ์ธ์ ๋ชป ํฉ๋๋ค. ํ์ค์ ์ผ๋ก๋ ๋น๋ฐ๋ฒํธ์ passkey๊ฐ ๊ณต์กดํด์ผ ํฉ๋๋ค.
Conditional UI๊ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ๋ณ๋์ "ํจ์คํค๋ก ๋ก๊ทธ์ธ" ๋ฒํผ ์์ด, ๊ธฐ์กด ์ด๋ฉ์ผ ์ ๋ ฅ ํ๋์ ์๋ ์์ฑ ๋ชฉ๋ก์ passkey ์ต์ ์ด ๋ํ๋ฉ๋๋ค. ๋น๋ฐ๋ฒํธ ์๋ ์์ฑ ์์ passkey๊ฐ ํจ๊ป ๋จ๋ ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
๊ตฌํ์ ์ธ ๋จ๊ณ์ ๋๋ค.
<!-- 1๋จ๊ณ: input์ webauthn ํํธ ์ถ๊ฐ -->
<input
type="text"
name="username"
autocomplete="username webauthn"
placeholder="์ด๋ฉ์ผ ๋๋ ์ฌ์ฉ์ ์ด๋ฆ"
/>
// 2๋จ๊ณ: ๋ธ๋ผ์ฐ์ ๊ฐ ์ด ๊ธฐ๋ฅ์ ์ง์ํ๋์ง ํ์ธ
if (await PublicKeyCredential.isConditionalMediationAvailable()) {
// 3๋จ๊ณ: mediation: 'conditional'๋ก ํธ์ถ
const assertion = await navigator.credentials.get({
publicKey: {
challenge: serverChallenge,
rpId: 'example.com',
allowCredentials: [],
userVerification: 'preferred',
},
mediation: 'conditional', // ์ด๊ฒ ํต์ฌ
});
}
mediation: 'conditional'์ด ์์ผ๋ฉด navigator.credentials.get()์ ์ฆ์ ๋ชจ๋ฌ ํ์
์ ๋์๋๋ค. 'conditional'์ ์ฃผ๋ฉด ํ์
๋์ ์๋ ์์ฑ ๋ชฉ๋ก์ ์กฐ์ฉํ ๋ผ์ด๋ญ๋๋ค. ์ฌ์ฉ์๊ฐ passkey๋ฅผ ์ ํํ๋ฉด ๊ทธ๋ ์์ฒด์ธ์์ด ์์๋๊ณ , passkey๊ฐ ์์ผ๋ฉด ๊ธฐ์กด๋๋ก ๋น๋ฐ๋ฒํธ๋ฅผ ์
๋ ฅํฉ๋๋ค.
๋ฐ๋ ๋ฐฉํฅ๋ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ๋น๋ฐ๋ฒํธ๋ก ๋ก๊ทธ์ธ์ ์ฑ๊ณตํ ํ, ์๋ ์์ฑ ์์ญ์ "์ด ์ฌ์ดํธ์ ํจ์คํค ๋ง๋ค๊ธฐ" ์ต์ ์ ํ์ํฉ๋๋ค. ๋ณ๋ ํ์ด์ง๋ก ๋ณด๋ด๊ฑฐ๋ ๋ฐฐ๋๋ฅผ ๋์ฐ์ง ์์๋, ๋น๋ฐ๋ฒํธ ์ฌ์ฉ์๋ฅผ passkey๋ก ์์ฐ์ค๋ฝ๊ฒ ์ ํํ ์ ์์ต๋๋ค. ํ์ฌ Safari์ ์ผ๋ถ ํจ์ค์๋ ๋งค๋์ ์์ ์ง์ํฉ๋๋ค.
๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ค ๊ณต๊ฒฉ์ ๋ง์ ์ ์๋์ง ๋น๊ตํด๋ณด๊ฒ ์ต๋๋ค.
| ๊ณต๊ฒฉ ์ ํ | ๋น๋ฐ๋ฒํธ | OTP (TOTP/SMS) | Passkey |
|---|---|---|---|
| ํผ์ฑ | ๊ฐ์ง ์ฌ์ดํธ์ ์ ๋ ฅํ๋ฉด ๋ | ์ค์๊ฐ ์ค๊ณํ๋ฉด ๋ซ๋ฆผ | ์ฐจ๋จ. ๋๋ฉ์ธ์ด ๋ค๋ฅด๋ฉด ์์ ๋์ ์ ํจ |
| ์๋ฒ ํดํน | ํด์ ์ ์ถ โ ํฌ๋ํน ๊ฐ๋ฅ | ์๋ ์ ์ถ โ OTP ์์ฑ ๊ฐ๋ฅ | ๋ฌด์๋ฏธ. ๊ณต๊ฐ ํค๋ง ์์ด์ ํ ์ ์๋ ๊ฒ ์์ |
| ํฌ๋ฆฌ๋ด์ ์คํฐํ | ๊ฐ์ ๋น๋ฐ๋ฒํธ๋ฅผ ๋ค๋ฅธ ์ฌ์ดํธ์ ์๋ | ํด๋น ์์ | ๋ถ๊ฐ. ํค ์์ด ๋๋ฉ์ธ๋ณ๋ก ๋ค๋ฆ |
| ์ค๊ฐ์ ๊ณต๊ฒฉ | ๊ฐ์ ๊ฐ๋ก์ฑ์ ๊ทธ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ | ์ค์๊ฐ OTP ์ค๊ณ ๊ฐ๋ฅ | ์ฐจ๋จ. ์ฑ๋ฆฐ์ง ์๋ช ์ด origin์ ๋ฌถ์ฌ ์์ |
๋น๋ฐ๋ฒํธ์ OTP๊ฐ ํผ์ฑ์ ์ทจ์ฝํ ๊ทผ๋ณธ ์์ธ์, ์ฌ์ฉ์๊ฐ ๊ฐ์ ๋์ผ๋ก ์ฝ๊ณ ์์ผ๋ก ์
๋ ฅํ๋ ๊ตฌ์กฐ์ด๊ธฐ ๋๋ฌธ์
๋๋ค. examp1e.com(์ซ์ 1)๊ณผ example.com(์ํ๋ฒณ l)์ ๋งค๋ฒ ๊ตฌ๋ถํ๊ธด ์ด๋ ต์ต๋๋ค.
Passkey์์๋ ์ฌ์ฉ์์ ํ๋จ์ด ๊ฐ์ ํ์ง ์์ต๋๋ค.
1. ์๋ฒ๊ฐ rpId: 'example.com'์ผ๋ก ์ฑ๋ฆฐ์ง ๋ฐ๊ธ
2. ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฌ ํ์ด์ง์ origin๊ณผ rpId๋ฅผ ๋น๊ต
3. evil-example.com โ example.com โ ์ธ์ฆ๊ธฐ์ ์์ฒญ ์์ฒด๋ฅผ ์ ๋ณด๋
4. ์ฌ์ฉ์์๊ฒ passkey ์ ํ์ง๊ฐ ์์ ํ์๋์ง ์์
์ด ๊ฒ์ฆ์ ๋ธ๋ผ์ฐ์ ๋ด๋ถ์์ ์ํ๋ฉ๋๋ค. JavaScript๋ก ์ฐํํ ์ ์์ต๋๋ค.
Passkey ์์ฒด์ ์ํธํ์ ์์ ํ์ง๋ง, ์ธ์ฆ ์์คํ ์ ์ฒด๊ฐ ์์ ํ ๊ฑด ๋ณ๊ฐ์ ๋๋ค.
์๋ฅผ ๋ค์ด Proofpoint ์ฐ๊ตฌํ์ด ๋ฐ๊ฒฌํ Microsoft Entra ID ๊ณต๊ฒฉ์ด ์์ต๋๋ค. ํผ์ฑ ํ๋ก์๊ฐ "์ด ๋ธ๋ผ์ฐ์ ๋ passkey๋ฅผ ์ง์ํ์ง ์์ต๋๋ค"๋ผ๊ณ ๊ฑฐ์ง๋งํ๋ฉด, Entra๊ฐ passkey๋ฅผ ๋นํ์ฑํํ๊ณ ๋น๋ฐ๋ฒํธ ํด๋ฐฑ์ผ๋ก ์ ๋ํฉ๋๋ค. ์ฌ์ฉ์๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํ๊ฒ ๋๊ณ , ๊ทธ๊ฑธ ๊ณต๊ฒฉ์๊ฐ ๊ฐ๋ก์ฑ๋๋ค.
์ด๊ฑด passkey์ ๊ฒฐํจ์ด ์๋๋ผ ํด๋ฐฑ ๊ฒฝ๋ก์ ์ค๊ณ ๋ฌธ์ ์ ๋๋ค. Passkey์ ๋ณด์์ ์จ์ ํ ์ป์ผ๋ ค๋ฉด, ์ฝํ ์ธ์ฆ ์๋จ์ผ๋ก์ ํด๋ฐฑ์ ์์ ๊ฑฐ๋ ์ถ๊ฐ ๊ฒ์ฆ์ ๊ฑธ์ด์ผ ํฉ๋๋ค.
์ธ์ฆ๊ธฐ๋ ์ธ์ฆํ ๋๋ง๋ค ๋ด๋ถ ์นด์ดํฐ(signCount)๋ฅผ 1์ฉ ์ฌ๋ฆฝ๋๋ค. ์๋ฒ๋ "์ง๋๋ฒ์ 42์๋๋ฐ ์ด๋ฒ์ 43์ด ์์ผ๋ ์ ์"์ด๋ผ๊ณ ํ๋จํฉ๋๋ค. ๋ง์ฝ 42 ์ดํ๊ฐ ์ค๋ฉด ์ธ์ฆ๊ธฐ๊ฐ ๋ณต์ ๋์์ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
์๋ฒ์ ์ ์ฅ๋ signCount: 42
โ ์ด๋ฒ ์์ฒญ์ signCount๊ฐ 43 โ ์ ์
โ ์ด๋ฒ ์์ฒญ์ signCount๊ฐ 42 ์ดํ โ ๋ณต์ ์์ฌ โ ๊ฒฝ๊ณ ๋๋ ์ฐจ๋จ
๋ค๋ง synced passkey๋ ์ฌ๋ฌ ๊ธฐ๊ธฐ์์ ๋์์ ์ธ ์ ์์ด์, ์นด์ดํฐ๊ฐ ์์๋๋ก ์ฆ๊ฐํ์ง ์์ ์ ์์ต๋๋ค. ์ผ๋ถ ํ๋ซํผ์ synced passkey์ signCount๋ฅผ ํญ์ 0์ผ๋ก ๋ฐํํฉ๋๋ค. ํ๋์จ์ด ๋ณด์ ํค ๊ฐ์ device-bound credential์์๋ ์ฌ์ ํ ์ ํจํ ํ์ง ์๋จ์ ๋๋ค.
๋ฑ๋กํ ๋ ์ธ์ฆ๊ธฐ๋ ์ ํ์ ์ผ๋ก attestation(์ฆ๋ช )์ ์ ๊ณตํ ์ ์์ต๋๋ค. "์ด ํค ์์ ์ธ์ฆ๋ฐ์ ํ๋์จ์ด์์ ๋ง๋ค์ด์ก์ต๋๋ค"๋ผ๋ ์ผ์ข ์ ์์ฐ์ง ์ฆ๋ช ์์ ๋๋ค.
| ์ ํ | ์๋ฏธ | ์ธ์ ์ฐ๋ |
|---|---|---|
| None | ์ฆ๋ช ์ ํจ. ์ธ์ฆ๊ธฐ๊ฐ ๋ญ๋ ์๊ด์์ | ์ผ๋ฐ ์๋น์ ์๋น์ค (๋๋ถ๋ถ ์ด๊ฑธ ์) |
| Self | ๋ฐฉ๊ธ ๋ง๋ ํค ์์ผ๋ก ์ค์ค๋ก ์๋ช | ์ธ์ฆ๊ธฐ ์ข ๋ฅ๋ฅผ ๊ตณ์ด ํ์ธ ์ ํ ๋ |
| Packed | ์ ์กฐ์ฌ๊ฐ ์ธ์ฆ๊ธฐ์ ์ฌ์ด๋ ์ธ์ฆ์๋ก ์๋ช | ํน์ ๋ชจ๋ธ๋ง ํ์ฉํ๊ณ ์ถ์ ๋ (๊ธฐ์ ์ฉ) |
| TPM | TPM 2.0 ์นฉ์ ํ์ค attestation | Windows Hello |
| Android Key | Android Keystore attestation | Android |
| Apple | Apple Anonymous Attestation | Apple ๊ธฐ๊ธฐ |
| FIDO U2F | ์ด์ ์ธ๋(CTAP1) ๋ณด์ ํค์ attestation | ๋ ๊ฑฐ์ ํธํ |
๋๋ถ๋ถ์ ์๋น์ค์์๋ attestation: 'none'์ด๋ฉด ์ถฉ๋ถํฉ๋๋ค. ์ด๋ค ์ธ์ฆ๊ธฐ๋ฅผ ์ฐ๋ ๊ณต๊ฐ ํค ๊ธฐ๋ฐ ์ธ์ฆ์ ๋ณด์ ์ด์ ์ ๋์ผํ๋๊น์. ๊ธฐ์
ํ๊ฒฝ์์ "๋ฐ๋์ FIDO Certified ํ๋์จ์ด ํค๋ง ํ์ฉ"ํ๊ณ ์ถ์ ๋ attestation ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค.
Passkey๋ง ์ง์ํ๊ณ ๋ค๋ฅธ ์ธ์ฆ ์๋จ์ด ์์ผ๋ฉด, ๋ชจ๋ ๊ธฐ๊ธฐ๋ฅผ ์์์ ๋ ๊ณ์ ์ ์ ๊ทผํ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
rp.id๋ credential์ ์๊ตฌ์ ์ผ๋ก ๋ฌถ์
๋๋ค. ์ฒ์์ ์ ์ ํด์ผ ํฉ๋๋ค.
rp.id๋ฅผ 'example.com'์ผ๋ก ์ค์ ํ๋ฉด:
example.com โ โ
์ฌ์ฉ ๊ฐ๋ฅ
app.example.com โ โ
ํ์ ๋๋ฉ์ธ์์๋ ์ฌ์ฉ ๊ฐ๋ฅ
other-domain.com โ โ ๋ถ๊ฐ
rp.id๋ฅผ 'app.example.com'์ผ๋ก ์ค์ ํ๋ฉด:
app.example.com โ โ
example.com โ โ ์์ ๋๋ฉ์ธ์์๋ ์ฌ์ฉ ๋ถ๊ฐ
๋์ค์ ์๋ธ๋๋ฉ์ธ์์๋ ์ธ ๊ฐ๋ฅ์ฑ์ด ์๋ค๋ฉด, rp.id๋ ๊ฐ์ฅ ์์ ๋๋ฉ์ธ(eTLD+1)์ผ๋ก ์ค์ ํ๋ ๊ฒ ์์ ํฉ๋๋ค.
example.com๊ณผ example.co.kr์ฒ๋ผ ์์ ๋ค๋ฅธ ๋๋ฉ์ธ์์ ๊ฐ์ passkey๋ฅผ ์ฐ๊ณ ์ถ๋ค๋ฉด? WebAuthn Level 3์ Related Origin Requests๋ฅผ ์ฌ์ฉํฉ๋๋ค.
https://example.com/.well-known/webauthn
์ด ํ์ผ์ ๊ด๋ จ ๋๋ฉ์ธ ๋ชฉ๋ก์ ์ ์ธํ๋ฉด, ๋ธ๋ผ์ฐ์ ๊ฐ cross-origin passkey ์ฌ์ฉ์ ํ์ฉํฉ๋๋ค.
FIDO Alliance์ ๋ฐ๋ฅด๋ฉด 10์ต ๋ช ์ด์์ด passkey๋ฅผ ํ์ฑํํ๊ณ , ์์ 100๊ฐ ์น์ฌ์ดํธ ์ค 48%๊ฐ passkey๋ฅผ ์ง์ํฉ๋๋ค.
๊ท์ ๋ ์์ง์ด๊ณ ์์ต๋๋ค. NIST SP 800-63-4(2025๋ 7์)๋ AAL2(์ธ์ฆ ๋ณด์ฆ ๋ ๋ฒจ 2)์์ ํผ์ฑ ๋ฐฉ์ง ์ต์ ์ ๊ณต์ ์๊ตฌํ๋ฉฐ, synced passkey๋ฅผ AAL2 ์ธ์ฆ๊ธฐ๋ก ์ธ์ ํฉ๋๋ค. UAE ์ค์์ํ์ 2026๋ 3์๊น์ง SMS/์ด๋ฉ์ผ OTP ์ ๊ฑฐ ์ง์นจ์ ๋ด๋ ธ์ต๋๋ค.
OAuth Deep Dive์์ ๋ค๋ค๋ฏ์ด OAuth๋ ์ธ๊ฐ(๋๊ฐ ์ด๋ค ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋๊ฐ) ํ๋กํ ์ฝ์ ๋๋ค. Passkey๋ ์ธ์ฆ(์ด ์ฌ๋์ด ๋๊ตฌ์ธ๊ฐ) ๋ฉ์ปค๋์ฆ์ ๋๋ค. ๋์ ๊ฒฝ์์ด ์๋๋ผ ๋ค๋ฅธ ๊ณ์ธต์ ๋ฌธ์ ๋ฅผ ํ๋๋ค.
์ฌ์ฉ์ โโ(Passkey๋ก ์ธ์ฆ)โโโ IdP (Google, Apple ๋ฑ)
โ
OAuth ํ ํฐ ๋ฐ๊ธ (์ธ๊ฐ)
โ
Client ์ฑ์ด API ์ ๊ทผ
Google ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด Google IdP์์ ๋ณธ์ธ ํ์ธ์ ํฉ๋๋ค. ์ด ๋จ๊ณ์์ ๋น๋ฐ๋ฒํธ ๋์ passkey๋ฅผ ์ฐ๋ ๊ฒ๋๋ค. ๊ทธ ๋ค์ OAuth Authorization Code ํ๋ฆ์ ๋ฐ๋์ง ์์ต๋๋ค.
Cookie Deep Dive์์ ๋ค๋ค๋ CSRF, XSS๋ ๋ก๊ทธ์ธ ์ดํ ์ธ์ ์ ๋ณดํธํ๋ ๋ฌธ์ ์ ๋๋ค. Passkey๋ ๋ก๊ทธ์ธ ์์ฒด๋ฅผ ๋ณดํธํฉ๋๋ค. Passkey๋ก ์์ ํ๊ฒ ๋ก๊ทธ์ธํ ๋ค์๋, ์ธ์ ์ฟ ํค์ ๋ณด์(HttpOnly, SameSite ๋ฑ)์ ๋ณ๋๋ก ์ ๊ฒฝ ์จ์ผ ํฉ๋๋ค.