우진.zip

개발하다 마주친 문제와 배운 것을 기록합니다.

카테고리 선택

전체 글

패스키를 잃어버리면: 추가 등록·삭제·계정 복구를 설계할 때

패스키로 로그인하는 과정은 짧다. 하지만 휴대폰을 바꾸거나 보안 키를 잃어버린 뒤에도 계정에 들어갈 수 있어야 한다. 등록한 키를 정리하다가 마지막 로그인 수단까지 지우는 경우도 생각해야 한다.

앞선 글에서는 패스키가 계정을 확인하는 원리를 살펴봤다. 이번에는 그 이후의 관리와 복구를 정리한다. 첫 글의 구현 정책과 연결되는 부분은 있지만, 아래 내용 전체를 구현하고 검증했다는 뜻은 아니다. 서비스를 설계할 때 구분해서 살펴볼 항목들이다.

휴대폰을 잃었다고 패스키까지 사라지는 것은 아니다

먼저 패스키가 어디에 보관되어 있는지 확인해야 한다. 동기화형 패스키는 같은 제공자의 다른 기기에서도 사용할 수 있다. 반면 기기에 묶인 패스키는 해당 기기나 보안 키를 사용할 수 없으면 그 키로 인증하기 어렵다.[1]

예를 들어 Apple은 iCloud Keychain으로 패스키를 동기화하고, 모든 기기를 잃었을 때를 위한 키체인 복구 절차도 제공한다. 1Password 역시 기기 분실과 계정 안의 데이터 상실을 구분하며, 다른 기기에서 계정에 로그인해 데이터에 접근하는 방법을 안내한다. 실제 복구 조건은 제공자와 계정 설정에 따라 다르다.[2][3]

여기에는 서로 다른 두 가지 복구가 있다. 패스키 제공자의 계정을 복구해 기존 패스키를 다시 사용하는 것, 그리고 로그인하려던 서비스의 계정을 복구해 새 패스키를 등록하는 것이다. 어느 쪽에 접근할 수 없는지부터 나눠야 안내도 정확해진다.

기기 분실 후 남은 패스키 또는 기존 인증 수단과 계정 복구를 통해 관리 권한을 확인하고 새 키를 등록하는 흐름
관리와 복구를 나눈 개념 흐름. 실제 인증·복구 조건은 서비스와 패스키 제공자 정책에 따라 다르다.

여러 기기에 있는 키와 여러 개의 키는 다르다

같은 패스키가 휴대폰과 노트북에 동기화되어 있다고 해서, 서비스에 서로 독립적인 패스키 두 개를 등록한 것은 아니다. 한 credential을 여러 기기에서 사용하는 경우와 별도 credential을 추가한 경우는 구분해야 한다.

서비스가 여러 패스키 등록을 지원한다면 다른 제공자나 별도의 보안 키에 예비 수단을 둘 수 있다. 한 제공자에 접근하지 못하는 상황까지 대비하려면 단순히 동기화된 기기 수만 세어서는 부족하다. 다만 예비 키도 실제로 사용할 수 있게 보관하고 관리해야 의미가 있다.[1]

관리 화면에는 사용자가 키를 알아볼 수 있는 이름과 등록일, 확인 가능한 최근 사용 시각 등을 보여주는 편이 좋다. 제공자 정보를 알 수 있다면 함께 표시한다. 동기화형 키에 특정 휴대폰 이름만 붙이면 그 기기에서만 쓰는 키로 오해할 수 있다.[4]

로그인되어 있어도 새 키 등록은 따로 확인한다

새 패스키를 추가하면 앞으로 그 키로 계정에 들어올 수 있다. 남아 있는 로그인 세션만으로 등록을 허용하면, 세션을 가져간 사람이 자기 키를 붙이는 경로가 생길 수 있다. 계정에 들어와 있다는 사실과 인증 수단을 바꿀 권한은 따로 다뤄야 한다.

첫 글의 서비스에서는 키 추가·삭제에 JWT 외의 재인증을 요구했다. 비밀번호를 다시 확인하고, OTP를 사용하는 계정에는 OTP도 요구하는 정책이었다. 다른 서비스라면 기존 패스키로 재인증하는 방식을 선택할 수도 있다. 중요한 것은 작업의 위험에 맞춰 확인 수단과 유효 시간을 정하는 것이다.

분실한 패스키를 삭제할 때 그 패스키로만 재인증하도록 만들면 사용자가 막힌다. 남아 있는 다른 수단이나 정식 계정 복구로 관리 권한을 얻는 경로도 필요하다. 이미 열린 세션이 있다는 이유로 이 확인을 생략하는 방식은 피해야 한다.

구현한 부분과 설계로 남은 부분

항목이 사례에서 확인한 범위
추가 등록비밀번호와 필요한 OTP 재인증 후 등록용 증명을 발급한다. 등록 요청은 증명과 계정 상태를 확인한다.
삭제삭제 대상과 사용자에 묶인 증명을 소비하고, 소유 관계를 확인한 뒤 서버의 credential을 지운다.
삭제한 키로 다시 로그인삭제 후 같은 키를 거절하는 테스트 정의와 당시 통합·가상 인증기 실행 기록이 있다.
마지막 키 보호기존 비밀번호·OTP 로그인은 유지한다. 마지막 키만 별도로 막는 정책·경고 UI 구현은 확인하지 못했다.
계정 복구패스키 전용 복구 서비스 구현이나 복구 완료 후 새 키 등록의 인수 결과는 확인하지 못했다. 아래 복구 흐름은 설계 시 검토할 내용이다.
제공자 보관함·기존 세션제공자 내부 키 삭제나 이미 발급한 모든 JWT의 전역 폐기를 이 삭제 API가 수행한다고 볼 근거는 없다.

아래 코드는 구현 대조 기록을 바탕으로 흐름만 남긴 설명용 발췌다. 회사·제품명과 서비스·메서드 이름은 일반 예제명으로 바꾸고, 주변 설정과 예외 처리는 생략했다. 그대로 복사해 실행하는 완성 예제나 이번 글에서 새로 컴파일한 코드는 아니다.

Java
var proof = attempts.consume(proofId,
        Purpose.DELETE, origin, user.id(), credentialId);
accountState.requireUnchanged(user, proof.accountState());
var credential = credentials.lock(credentialId);
requireOwner(credential, user.id());
credentials.delete(credential);
credentials.flush();

이 발췌가 보여주는 것은 작업별 증명, 계정 상태, 소유권과 서버 삭제의 순서다. 마지막 credential인지 검사하거나 복구 수단을 새로 마련하는 분기는 포함하지 않는다. 등록도 같은 원칙으로 등록용 증명을 소비하지만, 삭제용 증명을 등록에 재사용하지 않는다.

서비스에서 지우는 것과 보관함에서 지우는 것

서비스가 패스키 등록을 삭제하면 해당 credential로 들어오는 인증을 더 이상 받아들이지 않아야 한다. 그렇다고 사용자의 비밀번호 관리자에서도 반드시 동시에 사라지는 것은 아니다. 반대로 보관함에서 키를 지워도 서비스의 등록 목록에는 기록이 남을 수 있다.

WebAuthn에는 서버가 더 이상 받아들이지 않는 credential 정보를 제공자에 알리는 Signal API가 있다. 이런 기능을 활용할 수 있지만, 지원 여부를 확인해야 하며 알림만으로 모든 저장 위치의 삭제가 끝났다고 가정해서는 안 된다. 서버의 인증 거절은 별도로 보장해야 한다.[5]

또한 패스키 삭제와 기존 로그인 세션 종료는 서로 다른 처리이다. 분실이나 탈취가 의심되는 상황이라면 해당 키만 정리할지, 이미 발급된 세션도 종료할지 정책을 정해야 한다. 동기화된 같은 키를 서비스에서 폐기하면 다른 기기의 그 키도 사용할 수 없다는 점을 안내해야 한다.

실제 삭제 흐름의 대상은 서비스 DB에 저장한 credential이었다. 삭제한 키를 기기가 계속 가지고 있어도 서버가 그 등록을 찾지 못하면 로그인은 거절된다. 이는 제공자 보관함에서 항목이 사라졌다는 증거와는 다르다. 삭제 후 기존 키 거절 테스트도 서버 측 효과를 확인한 것으로 범위를 한정했다.

마지막 패스키를 지운 다음을 먼저 본다

삭제 확인창에서는 키 개수보다 남은 로그인 수단이 중요하다. 마지막 패스키를 지워도 비밀번호와 OTP로 로그인할 수 있는 계정과, 패스키만 사용하는 계정은 상황이 다르다.

첫 글의 서비스는 기존 비밀번호·OTP 로그인 경로를 유지했다. 다만 마지막 패스키를 삭제하기 전에 대체 수단을 강제하거나 경고하는 전용 흐름은 확인하지 못했다. 비밀번호·OTP까지 잃었을 때도 복구할 수 있다고 단정하려면, 실제 계정 복구 정책과 실행 결과를 별도로 확인해야 한다. 패스키만 사용하는 서비스라면 다른 키나 복구 수단을 먼저 마련하도록 하는 정책을 검토해야 한다.

예를 들어 “이 키를 삭제하면 패스키로 로그인할 수 없습니다. 이후에는 비밀번호와 OTP를 사용하세요”처럼 결과를 구체적으로 알려주는 편이 낫다. 실제로 지원하지 않는 복구 수단을 안내하거나, 복구 가능 여부를 확인하지 않고 삭제 완료 화면만 보여줘서는 안 된다.

복구까지 포함해서 로그인 정책을 정한다

패스키가 피싱에 강해도, 계정 복구가 쉽게 통과되는 우회로라면 계정 전체의 보호 수준은 낮아질 수 있다. 이메일 링크나 문자 코드 같은 대체 수단을 둘 때는 편의성뿐 아니라 그 수단을 빼앗겼을 때의 영향도 함께 봐야 한다. 복구는 어떤 증거로 계정 소유자를 다시 확인할지 정하는 절차이다.

복구를 마친 뒤에는 새 패스키 등록을 안내하고, 더 이상 신뢰할 수 없는 키와 세션을 정리할 수 있게 한다. 사용자가 직접 요청한 복구와 의심스러운 접근에 따른 복구를 같은 상황으로 취급하지 않는 것도 중요하다.[6]

새 키 등록이나 삭제, 복구 완료처럼 로그인 수단이 바뀌는 작업에는 사용자 알림도 고려할 만하다. 알림에는 변경 시각과 작업 내용, 본인이 한 일이 아닐 때 확인할 경로를 담는다. 다만 알림 자체가 사전에 필요한 본인 확인을 대신해 주지는 않는다.

패스키 도입은 로그인 버튼 하나를 추가하는 데서 끝나지 않는다. 정상적으로 들어오는 경로를 만든 뒤에는 키를 바꾸는 과정과 모든 수단을 잃었을 때의 경로를 함께 확인해야 한다. 이번 연재에서는 기존 인증 정책에 패스키를 연결하는 일부터 인증 원리, 관리와 복구까지 그 범위를 나눠 살펴봤다.

이번 사례의 근거는 세 층으로 나눠 읽었다. 테스트 정의에는 여러 credential의 독립성, 다른 사용자·용도의 증명 혼용 거절, 계정 상태 변경 후 증명 거절, 인증·삭제 동시 처리의 경계가 있다. 보관된 실행 기록은 당시 통합 테스트와 비OTP·OTP 가상 인증기 흐름의 결과다. 실제 기기 확인은 전달받은 Windows Chrome·1Password 수동 결과로 한정한다. 마지막 키 보호·패스키 전용 복구·제공자 보관함 삭제·모든 세션 폐기·Windows Hello와 실제 모바일 인수까지 이 결과에 포함하지 않는다.

코드와 테스트 정의를 읽은 것, 과거 실행 결과를 확인한 것, 이번에 새로 실행한 것은 서로 다르다. 이 글을 보강하면서 새 제품 테스트나 배포를 수행한 것은 아니다. 구현하지 않은 복구 정책은 다음 설계 과제로 남기되, 구현된 등록·삭제 흐름과 섞지 않는 것이 이번 정리의 기준이다.

참고 자료

  1. FIDO Alliance: Passkeys
  2. Apple: About the security of passkeys
  3. 1Password: If your device was lost or stolen
  4. Android Developers: Manage passkeys
  5. W3C: WebAuthn Level 3, Signal methods
  6. Google: Passkeys user journeys

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다