"패스키를 달면 끝" 이 아닙니다. 패스키는 로그인 화면 하나를 바꾸는 일이 아니라, 사용자가 잃어버릴 수 있는 것(기기, 계정, 생체 정보)과 서버가 믿는 것(공개키, challenge, origin)을 다시 정리하는 일입니다. 이 글은 구현 라이브러리 나열 대신 비밀번호와의 차이, WebAuthn 에 등장하는 역할, 그리고 실제로 도입을 검토하면서 가장 오래 걸렸던 복구 설계를 정리합니다. 작은 B2B 서비스에 패스키를 붙이는 검토를 하면서 적은 기준입니다.
사용자가 체감하는 차이#
비밀번호는 결국 기억하거나 적어 둔 공유 비밀 입니다. 서버도 알고(해시 형태로) 사용자도 알기 때문에 유출, 재사용, 피싱에 노출됩니다. 패스키는 기기나 OS 가 보관하는 비대칭 키 입니다. 서버에는 공개키만 남고, 개인키는 기기 밖으로 나가지 않습니다. 키가 도메인에 묶이기 때문에 가짜 사이트에서는 같은 키가 작동하지 않습니다. "패스키는 피싱에 강하다" 는 말이 나오는 이유입니다.
사용자 입장에서는 "비밀번호 입력" 이 "지문·얼굴 확인" 으로 바뀌는 것이 전부처럼 보입니다. 그런데 복구 는 오히려 어려워집니다. 비밀번호는 "이메일로 재설정" 한 번이면 끝나던 흐름이, 패스키만으로 가면 기기를 바꾸거나 잃어버렸을 때 다른 기기 등록, 백업 키, 사람이 확인하는 절차 같은 설계가 필요해집니다. 도입 검토에서 시간이 가장 많이 든 지점이 여기였습니다.
WebAuthn 의 세 역할#
스펙 문서에 나오는 세 이름만 정리돼 있어도 문서가 절반은 읽힙니다.
- Relying Party(RP). 우리 서비스의 백엔드와 도메인입니다. challenge 를 만들고, 서명을 검증하고, 공개키를 저장합니다.
- 클라이언트(브라우저).
navigator.credentials로 OS 의 인증 UI 를 띄우고, 어느 출처(origin)에서 요청했는지를 Authenticator 에 전달합니다. - Authenticator. 키를 실제로 보관하고 서명하는 쪽입니다. 플랫폼 내장(폰의 보안 칩, 노트북의 TPM)일 수도 있고, 외장 보안 키일 수도 있습니다.
패스키가 피싱에 강한 이유는 브라우저가 origin 을 Authenticator 에 넘기고, 키가 그 origin 에 묶여 있어서입니다. 가짜 도메인에서는 맞는 키를 찾지 못합니다.
Next.js 백엔드에서의 흐름#
App Router 기준으로 보통 아래처럼 갑니다.
- 등록. Route Handler 가 challenge 를 만들어 세션에 저장하고 클라이언트에 보냅니다. 브라우저가 Authenticator 로 키를 만들고 공개키·credentialId 를 돌려주면, 서버가 challenge 와 origin 을 확인한 뒤 사용자에게 연결해 저장합니다.
- 로그인. 서버가 새 challenge 를 발급하고, 브라우저가 Authenticator 서명을 받아 보내면, 서버가 저장된 공개키로 서명을 검증하고 세션 쿠키를 발급합니다.
서명 검증과 credentialId 매핑은 검증된 라이브러리를 씁니다. ASN.1 파싱이나 COSE 키 처리를 직접 짜는 것은 피하는 것이 맞습니다. 세션은 기존 방식 그대로 두고, "어떤 인증 수단으로 세션이 열렸는지" 만 기록해 두면 나중에 수단별 정책을 둘 수 있습니다.
검토하면서 막혔던 것. challenge 를 어디에 두느냐입니다. 서버 메모리에 두면 인스턴스가 여러 개일 때 깨지고, 쿠키에 두면 크기와 만료를 따로 관리해야 합니다. 작은 서비스에서는 서버 세션 저장소(Redis 등)에 짧은 만료로 두는 것이 가장 단순했습니다.
복구 설계: 결정해야 할 것#
패스키 도입에서 실제로 결정해야 하는 것은 로그인이 아니라 복구입니다. 아래 질문에 답이 없으면 출시 후 고객 문의가 몰립니다.
| 상황 | 결정할 것 |
|---|---|
| 기기를 바꿨다 | OS 계정 동기화(iCloud 키체인 등)로 패스키가 따라오는가, 안 따라오는 경우 어떻게 하는가 |
| 기기를 잃어버렸다 | 두 번째 기기 등록을 처음부터 권장할 것인가, 이메일·SMS 같은 보조 수단을 둘 것인가 |
| 패스키를 지워 버렸다 | 비밀번호를 남겨 둘 것인가, 남긴다면 패스키의 보안 이점이 얼마나 줄어드는가 |
| 회사 기기만 쓰는 사용자 | 기업 정책으로 생체 인증이 막힌 경우 외장 키를 허용할 것인가 |
| 아무것도 안 된다 | 사람이 확인하는 복구 절차(본인 확인 자료, 대기 시간)를 둘 것인가 |
저희 검토에서는 "비밀번호를 당분간 남기고, 패스키를 두 개 이상 등록하도록 유도하며, 이메일 복구는 유지" 로 결론이 났습니다. 보안 이점은 줄지만 고객 지원 비용이 현실적이었습니다. 이 결정은 서비스마다 다르고, 정답이 있다기보다 어느 비용을 감수할지의 문제입니다.
점진 도입을 권하는 이유#
이미 비밀번호와 MFA 를 쓰는 서비스라면, 비밀번호와 패스키를 병행 한 뒤 로그인 화면에서 패스키를 조금씩 앞으로 당기는 방식이 운영 위험이 적습니다. 순서는 보통 이렇습니다.
- 설정 화면에서 패스키 등록을 "선택" 으로 연다.
- 등록한 사용자에게 로그인 시 패스키를 먼저 제안한다.
- 등록률과 복구 문의를 몇 주 본다.
- 특정 사용자군(사내 사용자, 관리자)부터 패스키 필수로 바꾼다.
팀에는 "패스키가 비밀번호를 대체할 수 있는가" 보다 "어떤 사용자군부터 시도할지" 를 먼저 정하자고 말하는 편입니다. 전체 전환을 한 번에 하면 복구 문의가 한꺼번에 몰립니다.
정리#
패스키는 인증 UX 와 보안 구조를 동시에 바꾸는 결정입니다. 로그인 코드는 라이브러리가 해결해 주지만, 복구 절차와 사용자군별 전환 순서는 서비스가 직접 정해야 합니다. 이 글은 그 결정에 필요한 개념 지도만 그렸고, 실제 도입 때는 브라우저·OS 지원 범위, 기업 정책, 규제 요구를 릴리즈 노트 수준까지 따라가야 합니다.
문의 폼처럼 작은 지점에서 개인정보 처리를 정리하는 방법은 문의 폼 개인정보 처리 정리 글에, 장애가 났을 때의 대응 기준은 장애 대응과 SLA에 따로 적었습니다.

