1. 패스워드의 한계와 Passkey의 등장
전통적인 패스워드 인증의 문제점
우리는 수십 개의 온라인 서비스에 가입하며 그만큼의 비밀번호를 관리해야 한다. 간단한 비밀번호를 사용하면 보안 위험에 노출되고, 복잡한 비밀번호를 만들면 기억하기 어렵다. 결국 많은 사용자들이 동일한 비밀번호를 여러 사이트에서 재사용하거나, 메모장에 저장하는 위험한 행동을 한다.
비밀번호 기반 인증의 근본적인 문제점은 다음과 같다:
보안 취약점: 비밀번호는 입력 과정에서 도청되거나, 서버에 저장된 비밀번호 데이터가 유출될 수 있다. 크리덴셜 스터핑(Credential Stuffing) 공격으로 다양한 서비스에서 동시에 로그인을 시도하는 위협도 증가하고 있다. FIDO 얼라이언스의 연구에 따르면 피싱 공격으로 인한 계정 탈취 사건의 99% 이상이 비밀번호 기반 인증에서 발생한다.
사용자 편의성: 비밀번호 변경, 재설정, 복잡한 요구사항 준수 등의 과정이 번거롭다. 한 조사에서 기존 인증 시스템의 가장 불편한 점으로 "비밀번호 자주 변경"(48.5%), "비밀번호 재설정"(43.4%), "외우기 어려움"(37%)이 꼽혔다.
개인정보 보호 우려: 서버에 비밀번호를 저장하는 것 자체가 데이터 유출 위험을 야기한다. 해시 함수로 암호화하더라도 완전한 보안을 보장하지 못한다.
Passkey가 해결하려는 근본적인 문제
Passkey는 이러한 문제들을 근본적으로 해결하기 위해 등장했다. 가장 핵심적인 차이는 비밀번호를 완전히 제거하는 것이다.
Passkey는 생체 인증(지문, 얼굴 인식)이나 PIN, 보안 키 같은 수단으로 기기 자체에서 인증을 수행한다. 개인 암호화 키는 절대 서버로 전송되지 않으며, 사용자의 기기에만 안전하게 보관된다. 이는 서버에 저장된 정보가 유출되더라도 공격자가 개인 키에 접근할 수 없다는 뜻이다.
더 중요한 것은 Passkey의 도메인 바인딩(Domain Binding) 특성이다. 특정 도메인(예: example.com)에서 생성된 Passkey는 피싱 사이트(malicious-example.com)에서는 작동하지 않는다. 이는 기술 자체에 내장된 피싱 방지 기능으로, 사용자가 URL을 잘못 확인해도 공격자가 개인 키를 탈취할 수 없다.
2. Passkey란 무엇인가?
기본 개념과 정의
Passkey(패스키)는 공개키 암호화 방식을 기반으로 한 차세대 로그인 수단이다. 비밀번호 없이 기기의 생체 인증 정보와 암호화 키 쌍을 이용해 신원을 증명하는 방식이다.
사용자가 특정 서비스에 Passkey를 등록하면:
- 기기에서 키 쌍 생성: 사용자의 스마트폰, 태블릿, PC 등의 기기에서 공개키(Public Key)와 개인키(Private Key)의 한 쌍을 자동으로 생성한다.
- 공개키 서버에 저장: 공개키만 서비스 제공자의 서버에 저장된다. 이 공개키는 무해한 정보로, 누구나 볼 수 있어도 문제없다.
- 개인키는 기기에만 보관: 개인키는 절대 서버로 전송되지 않으며, 사용자의 기기에 암호화되어 안전하게 보관된다.
로그인할 때는 다음과 같이 진행된다:
- 사용자가 로그인 버튼을 클릭한다.
- 기기에 저장된 개인키에 접근하기 위해 생체 인증(지문, 얼굴)이나 PIN을 입력한다.
- 기기에서 인증이 성공하면, 개인키로 서버의 챌린지(임시 난수)에 서명한다.
- 서명 데이터가 서버로 전송되고, 서버는 저장된 공개키로 서명을 검증한다.
- 검증이 성공하면 로그인이 완료된다.
FIDO2/WebAuthn 표준과의 관계
Passkey는 FIDO2 표준을 기반으로 한다. FIDO(Fast Identity Online)는 인터넷 인증을 표준화하기 위한 업계 연합으로, Apple, Google, Microsoft 등 주요 기술 기업들이 참여하고 있다.
FIDO2의 진화 과정:
- FIDO U2F (2014): 기존 비밀번호에 추가 인증 단계를 더하는 2단계 인증 표준
- FIDO2 (2018): 비밀번호를 완전히 대체하는 passwordless 인증 표준으로 진화
WebAuthn(Web Authentication)은 W3C(World Wide Web Consortium)에서 2019년 표준화한 웹 API로, FIDO2 기술을 웹 브라우저에서 사용할 수 있게 만들었다. 개발자는 WebAuthn API를 통해 Passkey 기능을 웹 애플리케이션에 구현할 수 있다.
Passkey와 WebAuthn의 관계: Passkey는 WebAuthn 표준을 기반으로 구현된 서비스/기능이다. WebAuthn이 기술 표준이라면, Passkey는 Apple, Google, Microsoft 같은 플랫폼 업체들이 자신의 플랫폼에 통합한 사용자 친화적인 구현 방식이라고 보면 된다.
3. Passkey의 동작 원리
공개키 암호화의 기본 개념
Passkey는 공개키 암호화(비대칭 암호화) 방식을 기반으로 한다. 핵심은 다음과 같다:
- 공개키(Public Key): 서버에 저장되며, 데이터 검증에만 사용된다
- 개인키(Private Key): 사용자의 기기에만 보관되며, 데이터 서명에만 사용된다
개인키로 서명한 데이터는 공개키로만 검증할 수 있고, 공개키로는 서명을 생성할 수 없다. 따라서 공개키가 노출되어도 공격자는 개인키를 복원할 수 없다. Passkey 로그인은 이 원리를 활용해, 기기가 개인키로 서버의 Challenge에 서명하고, 서버가 공개키로 그 서명을 검증하는 방식으로 사용자의 신원을 확인한다.
등록과 인증의 흐름
Passkey 등록 (Registration)
- 사용자가 "Passkey 등록" 요청
- 서버는 일회용 난수(Challenge)를 생성해 클라이언트로 전송
- 기기의 Authenticator가 공개키/개인키 쌍을 생성하고, 공개키를 등록 증명(Attestation)과 함께 서버로 전송
- 개인키는 기기의 안전한 저장소(iOS Secure Enclave, Android KeyStore)에만 보관
- 서버는 공개키를 사용자 계정에 저장
Passkey 인증 (Authentication)
- 사용자가 로그인 시도
- 서버는 새로운 Challenge를 생성해 클라이언트로 전송
- 사용자가 생체 인증(지문, 얼굴)이나 PIN으로 기기 인증
- Authenticator가 개인키로 Challenge에 서명하고, 서명 데이터(Assertion)를 서버로 전송
- 서버는 저장된 공개키로 서명을 검증해 로그인 완료
Challenge의 역할은 매우 중요하다. 서버가 발급한 unique한 Challenge를 매번 새로 생성하므로, 공격자가 이전의 로그인 정보를 재사용하는 Replay Attack을 원천 차단한다.
도메인 바인딩과 생체인증
Passkey의 보안 강점은 두 가지 메커니즘에서 비롯된다.
도메인 바인딩 (Domain Binding)
Passkey는 특정 도메인(예: example.com)에서만 작동한다. 등록 시 서버의 RP ID(Relying Party ID)와 도메인 정보가 Challenge와 함께 서명되므로, 다른 도메인(예: evil.com)에서는 이 서명을 재사용할 수 없다. 따라서 피싱 공격으로 비슷한 도메인에 접속해도 Passkey로 로그인할 수 없다. 이는 비밀번호 기반 인증에서는 불가능한 보안 특성이다.
생체인증의 연계
개인키는 기기에 저장되지만, 사용할 때마다 생체 인증(지문, Face ID, Windows Hello 등)이 필요하다. 이는 기술적으로 "당신이 가진 것(기기 + 개인키) + 당신이 아는 것(생체 정보)"의 2단계 인증 효과를 제공한다. 핵심은 생체 데이터가 서버로 전송되지 않고 기기에서만 처리된다는 점이다. 또한 여러 기기에서 각각 다른 Passkey를 등록할 수 있으며, 클라우드 동기화(Apple Keychain, Google Password Manager)를 통해 여러 기기에서 하나의 Passkey를 사용할 수도 있다.
4. 웹개발자가 알아야 할 기술 스택
WebAuthn API 개요
WebAuthn은 JavaScript를 통해 Passkey 기능을 웹 애플리케이션에 구현하기 위한 W3C 표준 API다.
핵심 메서드:
// Passkey 등록
navigator.credentials.create({
publicKey: {
challenge: <ArrayBuffer>, // 서버에서 받은 난수
rp: {
name: "서비스명",
id: "example.com" // RP ID (도메인)
},
user: {
id: <ArrayBuffer>, // 사용자 ID
name: "username",
displayName: "사용자명"
},
pubKeyCredParams: [
{ alg: -7, type: "public-key" } // ECDSA 알고리즘
],
authenticatorSelection: {
authenticatorAttachment: "platform", // 플랫폼 인증기
residentKey: "required" // 발견 가능한 자격증명
}
}
})
// Passkey로 로그인
navigator.credentials.get({
publicKey: {
challenge: <ArrayBuffer>,
rpId: "example.com",
timeout: 60000,
userVerification: "required" // 생체 인증 필수
}
})
반환 값:
- 등록 시: PublicKeyCredential 객체로 공개키와 Attestation 데이터 포함
- 인증 시: 서명이 포함된 Assertion 데이터 반환
Credential Management API
Credential Management API는 WebAuthn을 포함한 더 넓은 범위의 자격증명 관리를 담당하는 API다.
WebAuthn은 이 API의 PublicKeyCredential 인터페이스를 확장하여 구현된다:
// 기본 구조
CredentialType: PublicKeyCredential
├─ id (자격증명 ID)
├─ response (등록/인증 응답)
└─ type: "public-key"
조건부 UI (Conditional UI):
최신 WebAuthn 구현에서는 조건부 UI를 지원하여 사용자 이름 입력 필드에 Passkey 선택지를 자동으로 표시할 수 있다:
// 조건부 UI 사용
navigator.credentials.get({
publicKey: { ... },
mediation: "conditional" // 자동 완성 스타일로 표시
})
// HTML 설정
<input type="text" autocomplete="webauthn username" />
브라우저 및 플랫폼 지원 현황
Passkey는 주요 브라우저와 플랫폼에서 지원되고 있다:
데스크톱 브라우저
- Chrome/Chromium: 67 이상 (2018년 5월부터)
- Safari: 13 이상이지만, Passkey 생체 인증은 macOS 12.3+(2021) /
Safari 15+ 필요. 이전 버전은 하드웨어 보안 키만 지원 - Firefox: 122 이상 (2024년 1월
- Edge: Chromium 기반으로 Chrome과 동일
모바일 플랫폼
- iOS/iPadOS: 16 이상 (Face ID, Touch ID로 Passkey 지원)
- iOS 13.3-15.x는 하드웨어 보안 키만 지원
- Android: 9 이상 권장 (Google Password Manager 기반 Passkey)
- 기술적으로는 Android 7.0+에서 WebAuthn 기본 지원
- Samsung Pass: Galaxy 기기에서 Passkey 저장소로 지원 (Android)
Authenticator 유형:
- 플랫폼 인증기 (Platform Authenticator):
- 기기에 내장된 인증 시스템
- 생체 인식 지원: Face ID, Touch ID, Windows Hello, Android Biometric
- 가장 사용자 친화적
- 크로스 플랫폼 인증기 (Cross-platform Authenticator):
- 보안 키 (USB, NFC, Bluetooth)
- 별도 기기로 여러 플랫폼에서 사용 가능
- 높은 보안성, 낮은 편의성
- 하이브리드 인증기:
- PC에서 스마트폰으로 생체 인증 요청
- BLE를 통한 연결
- 데스크톱과 모바일의 장점 결합
지원 확인 방법:
// WebAuthn 지원 여부 확인
if (window.PublicKeyCredential) {
// WebAuthn 지원
// 플랫폼 인증기 지원 여부
if (await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()) {
// 생체 인증 지원
}
}
5. 다음 편 예고
이번 편에서는 Passkey의 개념과 동작 원리, 기술 표준에 대해 알아봤다.
다음 편 "Passkey 구현 가이드 - 코드로 배우는 실전 구현"에서는:
- 개발 환경 설정: React, Express를 사용한 WebAuthn 라이브러리 통합
- 프론트엔드 구현: React에서
navigator.credentials.create(),navigator.credentials.get()호출 및 에러 처리 - 백엔드 구현: Challenge 생성, 공개키 저장, 서명 검증 로직
- 실제 코드 예시: 완전히 동작하는 등록과 로그인 구현
- 테스트 및 디버깅: 로컬 환경에서 효과적으로 테스트하는 방법
실전 구현 편에서 만날 다음 내용을 기대해주자!
'WebCommon' 카테고리의 다른 글
| Passkey 이해하기 2 - 코드로 배우는 실전 구현 (0) | 2025.12.24 |
|---|---|
| Access Token과 Refresh Token을 활용한 세션 관리 (0) | 2025.12.08 |
| GET, POST 뭐가 더 안전한 요청일까? (0) | 2025.12.05 |
| CLOUDFLARE로 이미지 업로드 (4) | 2024.09.13 |
| CSP 'upgrade-insecure-requests' 이슈 (1) | 2024.07.05 |