COMMENTS (0)
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
W3C WebAuthn 스펙 기반으로 Passkey/FIDO2의 등록·인증 플로우와 암호학적 구조를 분석하고 공격자 관점의 6가지 한계를 짚는다
댓글은 익명으로 작성되며, 삭제 비밀번호를 설정하면 본인만 삭제할 수 있습니다. 비밀번호를 설정하지 않은 댓글은 누구나 삭제할 수 있습니다.
2024년 Tycoon2FA 피싱 캠페인은 9만 6,000명의 MFA 인증을 무력화했다. 피해자들은 비밀번호를 입력하고, SMS 코드를 입력하고, 푸시 알림을 승인했다. 그래도 뚫렸다. 비밀번호든 OTP든, 서버와 사용자가 같은 비밀을 공유하는 한 공격자는 그 사이에 끼어들 수 있기 때문이다.
Passkey는 이 구조를 바꾼다. 서버에 비밀을 저장하지 않는다. 150억 개 이상의 온라인 계정이 이 방식을 지원하고, Amazon만 1억 7,500만 명이 등록했다. 이 글은 JWT(토큰 인증)와 OAuth 2.0(위임 인증)에 이어, 공유 비밀 없이 공개키 암호학만으로 인증을 완성하는 FIDO2/WebAuthn의 내부 구조를 분석한다.
비밀번호의 근본적 문제는 공유 비밀(shared secret)이라는 점이다. 사용자와 서버가 같은 비밀을 공유한다. 서버가 해시로 저장하더라도, 침해 시 오프라인 크래킹이 가능하다. 사용자가 여러 서비스에서 같은 비밀번호를 재사용하면 하나의 침해가 연쇄적으로 퍼진다.
SMS OTP나 TOTP(Google Authenticator 등)도 본질은 같다. 서버와 사용자가 시드(seed)를 공유하고, 시간 기반으로 동일한 코드를 생성한다. 서버가 탈취되면 모든 사용자의 2FA 코드를 생성할 수 있다.
Passkey는 이 구조를 근본적으로 바꾼다. 서버에는 공개키만 저장한다. 개인키는 사용자의 기기 안에서 나오지 않는다. 서버가 통째로 탈취되어도 공개키로 개인키를 복원할 수 없다.
용어가 혼재되어 있어 정리가 필요하다.
| 용어 | 정의 |
|---|---|
| FIDO2 | FIDO Alliance가 정의한 인증 표준의 총칭 |
| WebAuthn | W3C가 표준화한 브라우저 API (현재 Level 3) |
| CTAP2 | 인증기↔클라이언트 간 통신 프로토콜 |
| Passkey | FIDO2 자격증명의 사용자 친화적 명칭 |
WebAuthn은 브라우저가 navigator.credentials.create()와 navigator.credentials.get()을 통해 인증기와 통신하는 JavaScript API다. CTAP2(Client to Authenticator Protocol)는 브라우저와 하드웨어 보안키·생체인증 모듈 사이의 통신 규격이다.
Passkey는 두 종류로 나뉜다.
| 종류 | 저장 위치 | NIST 등급 |
|---|---|---|
| 동기화 패스키 | iCloud Keychain, Google Password Manager 등 클라우드 동기화 | AAL2 |
| 기기 바인딩 패스키 | TPM, Secure Enclave, 하드웨어 보안키 — 기기 외부로 나가지 않음 | AAL3 |
사용자가 서비스에 Passkey를 처음 등록하는 과정이다. W3C WebAuthn Level 3 스펙 기준으로 5단계로 진행된다.
1단계 — 서버가 챌린지를 생성한다. 서버는 PublicKeyCredentialCreationOptions를 구성한다. 무작위 챌린지(replay 방지), rp.id(도메인), user.id, 허용 알고리즘 목록(pubKeyCredParams)이 포함된다.
2단계 — 브라우저가 컨텍스트를 바인딩한다. 브라우저는 clientDataJSON을 생성한다. 여기에 type: "webauthn.create", 서버의 챌린지, 그리고 현재 페이지의 origin이 포함된다. 이 origin 바인딩이 피싱 차단의 핵심이다.
3단계 — 인증기가 키페어를 생성한다. Secure Enclave(Apple), TPM(Windows Hello), Android Keystore, 또는 하드웨어 보안키의 보안 요소 안에서 공개키/개인키 쌍이 생성된다. 개인키는 보안 요소 밖으로 나가지 않는다. 비밀번호가 사용자의 기억에 저장되고 서버에 복사본이 남는 것과 달리, 개인키는 하드웨어 안에만 존재하고 복사본이 어디에도 없다. 알고리즘은 ES256(P-256 ECDSA, COSE -7)이 가장 널리 지원된다.
4단계 — attestationObject가 생성된다. CBOR로 인코딩된 이 객체에는 authenticatorData가 포함된다. W3C 스펙이 정의한 바이트 구조는 다음과 같다.
| 필드 | 크기 | 내용 |
|---|---|---|
| rpIdHash | 32바이트 | RP ID의 SHA-256 해시 |
| flags | 1바이트 | UP(사용자 존재), UV(사용자 검증), BE(백업 가능), BS(백업 상태) |
| signCount | 4바이트 | 서명 카운터 (복제 탐지용) |
| attestedCredentialData | 가변 | AAGUID + credential ID + COSE 공개키 |
5단계 — 서버가 검증하고 공개키를 저장한다. 서버는 챌린지 일치, origin 일치, type 확인을 수행한 뒤 공개키와 credential ID를 데이터베이스에 저장한다. 이것이 서버가 보관하는 전부다. 개인키는 서버에 전송되지 않는다.
등록된 Passkey로 로그인하는 과정이다.
서버가 새 챌린지를 보내면, 인증기는 저장된 개인키로 authenticatorData || SHA256(clientDataJSON)을 서명한다. 서버는 등록 시 저장한 공개키로 이 서명을 검증한다. 서명이 유효하면 인증이 완료된다.
등록과 인증의 핵심 차이는 명확하다. 등록은 공개키를 서버에 전달하고, 인증은 공개키를 전달하지 않는다. 인증은 개인키 소유를 증명하는 서명만 전송한다.
Passkey의 피싱 저항은 사용자의 판단에 의존하지 않는다. 프로토콜 레벨에서 자동 차단된다.
인증 시 인증기는 브라우저가 전달한 origin을 확인한다. 비유하자면 이 열쇠는 특정 자물쇠에만 반응하도록 제작된 것이다. login.example.com에서 등록한 Passkey는 phishing-site.com에서 서명을 생성할 수 없다. 공격자가 AiTM(Adversary-in-the-Middle) 리버스 프록시로 로그인 페이지를 완벽히 복제하더라도, 프록시 도메인이 원래 서비스의 origin과 다르기 때문에 인증기가 동작하지 않는다.
1. 세션 하이재킹 — Passkey는 인증 시점만 보호한다. 인증 후 발급된 세션 토큰이 인포스틸러에 의해 탈취되면, Passkey 인증은 무의미해진다. 연간 86억 개의 세션 쿠키가 지하 시장에 유통된다.
2. 클라우드 계정 탈취 — 동기화 패스키의 보안 강도는 클라우드 계정(Apple ID, Google 계정)의 보안 강도와 같다. SIM 스와핑으로 클라우드 계정을 탈취하면, 패스키가 공격자 기기에 자동 동기화된다.
3. WebAuthn API 하이재킹 — 2025년 DEF CON 33에서 시연됐다. 악성 브라우저 확장 프로그램이 webAuthenticationProxy API로 WebAuthn 요청을 가로채 인증 프롬프트를 조작할 수 있다.
4. signCount 무력화 — WebAuthn 스펙은 signCount로 인증기 복제를 탐지하도록 설계했다. 그러나 Apple, Google, Microsoft 모두 동기화 패스키에서 signCount를 0으로 고정한다. 여러 기기 동기화와 양립할 수 없기 때문이다.
5. 복구 플로우 공격 — Passkey가 강해도 "기기를 잃어버렸어요" 복구가 이메일/SMS 기반이면 기존 피싱에 노출된다. 공격자의 전략이 자격증명 직접 탈취에서 복구 수단 공략으로 전환되고 있다.
6. 폴백 다운그레이드 — Passkey와 비밀번호를 병행하면, 전체 보안 강도는 비밀번호의 강도와 같다. 공격자는 Passkey 대신 비밀번호 폴백을 공격한다.
JWT는 서버 간 상태를 공유하는 문제를 해결했다. OAuth 2.0은 비밀번호를 제3자에게 노출하지 않고 권한을 위임하는 문제를 해결했다. Passkey는 공유 비밀 자체를 제거한다.
| 인증 방식 | 서버 저장 | 피싱 저항 |
|---|---|---|
| 비밀번호 | 해시 (침해 시 크래킹 가능) | 없음 |
| SMS/TOTP | 공유 시드 (서버 탈취 시 복원 가능) | 낮음 (AiTM에 취약) |
| Passkey | 공개키만 (탈취해도 무용) | 프로토콜 레벨 차단 |
한국에서는 카카오와 SK텔레콤 PASS가 패스키를 도입했지만, 금융권에서 FIDO2 패스키를 소비자 대상으로 도입한 기관은 아직 없다. 금융감독원의 전자금융감독규정이 인증 수단별 한도를 별도로 규정하고 있어, 새로운 인증 방식 도입에 규제 해석 부담이 크기 때문이다. 일본은 2026년 여름 증권사 의무화를 앞두고 있다. 기업 환경에서는 관리자 계정에 기기 바인딩 패스키(AAL3), 일반 직원에 동기화 패스키(AAL2)를 적용하는 계층별 전략이 권장된다.
Passkey가 인증 시점의 보안을 강화한다면, 인증 이후 세션 레이어의 보안은 별도 과제다. 세션 토큰이 탈취되면 Passkey 인증은 무의미해지기 때문이다.
AI 활용 안내 이 글은 AI(Claude)의 도움을 받아 작성되었습니다. 인용된 통계와 사례는 참고 자료에 명시된 출처에 근거하며, 설명을 위한 일부 표현은 각색되었습니다.
면책 조항 본 글은 보안 인식 제고를 위한 교육 목적으로 작성되었습니다. 언급된 공격 기법을 실제로 시도하는 행위는 「정보통신망법」, 「형법」 등에 따라 처벌받을 수 있으며, 본 블로그는 이에 대한 법적 책임을 지지 않습니다.