WebAuthn 비밀번호 없는 로그인
Doggy는 web-auth/webauthn-symfony-bundle 기반으로 WebAuthn 표준 인증을 구현하며 지문, 얼굴 인식, 보안 키 로그인을 지원합니다.
개요
WebAuthn 자격 증명은 src/Entity/Security/WebauthnCredential.php(테이블 webauthn_credentials)에 저장되며 App\Entity\Organization\Employee(사용자 엔티티)에 연결됩니다.
자격 증명 저장소는 PublicKeyCredentialSourceRepositoryInterface를 구현하여 WebAuthn 자격 증명의 저장과 조회를 지원합니다.
설정
yaml
# config/packages/webauthn.yaml
webauthn:
credential_repository: 'App\Repository\Security\WebauthnCredentialRepository'
user_repository: 'App\Repository\Organization\EmployeeRepository'
creation_profiles:
default:
rp:
name: '%env(RELYING_PARTY_NAME)%'
id: '%env(RELYING_PARTY_ID)%'
public_key_credential_parameters:
- -7 # ES256
- -257 # RS256
authenticator_selection_criteria:
resident_key: required
user_verification: required
request_profiles:
default:
rp_id: '%env(RELYING_PARTY_ID)%'
user_verification: required
allowed_origins: ['http://localhost:8000']보안 파이어월 설정
yaml
# config/packages/security.yaml
security:
firewalls:
main:
custom_authenticator: App\Security\AppCustomAuthenticator
webauthn:
success_handler: App\Security\WebauthnSuccessHandler
authentication:
enabled: true
routes:
options_path: '/login/webauthn/options'
result_path: '/login/webauthn/result'자격 증명 관리
php
// src/Entity/Security/WebauthnCredential.php
class WebauthnCredential
{
private string $publicKeyCredentialId;
private string $type; // 'public-key'
private array $transports; // ['usb', 'nfc', 'internal']
private string $attestationType;
private string $credentialPublicKey;
private string $userHandle; // Employee ID
private int $counter;
private ?string $deviceName; // 예: "Chrome on Mac"
#[ORM\ManyToOne(targetEntity: Employee::class, inversedBy: 'passkeys')]
private ?Employee $employee = null;
}로그인 흐름
Passkey 등록
- 사용자가 로그인 후 보안 설정 진입(
/user/webauthn/register/options) - 브라우저가 WebAuthn API를 호출하여 자격 증명 생성
- 결과를
/user/webauthn/register/result에 제출 - 공개 키 자격 증명을
webauthn_credentials테이블에 저장
비밀번호 없는 로그인
- 사용자 이름 입력, "Passkey 로그인" 클릭
- POST
/login/webauthn/options로 챌린지 획득 - 브라우저가 WebAuthn API를 호출하여 서명
- 결과를
/login/webauthn/result에 제출 WebauthnSuccessHandler가 로그인 성공 처리(장치 기록, 업데이트 시간)
성공 핸들러
App\Security\WebauthnSuccessHandler는 로그인 성공 후:
- 자격 증명의 마지막 사용 시간 업데이트
- 장치 이름 자동 인식(User-Agent 파싱)
- 최초 로그인 여부 확인, 비밀번호 변경 안내
- 비밀번호 재설정 흐름 지원
WebAuthn 자격 증명 저장소
App\Repository\Security\WebauthnCredentialRepository 구현:
findOneByCredentialId(): 자격 증명 조회findAllForUserEntity(): 사용자의 모든 자격 증명 가져오기saveCredentialSource(): 자격 증명 생성/업데이트parseUserAgent(): 장치 이름 인식