보안 가이드
비밀번호 재설정의 설계 결함: 로그인을 강화해도 계정이 탈취되는 5가지 경우와 해결책
비밀번호를 길게 하고 다중 인증을 켜도 '비밀번호를 잊으셨나요?'가 약하면 소용없습니다. 공격자는 로그인 대신 재설정으로 계정을 가져갑니다. 재설정 기능이 실제로 무너지는 5가지 형태, OWASP가 명시한 요구 사항, 그리고 가이드가 일부러 정하지 않고 남겨 둔 부분을 정하는 법을 정리합니다.
"비밀번호를 잊으셨나요?"를 누르면 나오는 것은 비밀번호를 모르는 사람이 새 비밀번호를 정하게 해 주는 장치입니다. 그러므로 이것은 하나의 인증 경로이고, 대개 그 서비스에서 가장 약한 경로입니다.
로그인 강화만으로는 막을 수 없는 이유
평소의 경로: 로그인
긴 비밀번호 · 다중 인증 · 요청 횟수 제한 · 무차별 대입 탐지
─────── 같은 계정 ───────
별도의 경로: 비밀번호 재설정
메일만 받으면 통과 · 두 번째 요소가 없는 경우가 많음 · 토큰 강도가 보이지 않음
재설정은 사용자 편의 기능으로 만들어지기 때문에 인증만큼 엄격하게 설계되거나 검토되지 않는 경우가 많습니다. 하지만 기능으로 보면, 비밀번호를 모르는 사람에게 계정의 통제권을 넘기는 일입니다. 로그인과 같은 범주에 속합니다.
이는 본 사이트가 2026년 일본 사고를 침입 방식별로 분류했을 때 확인한 것과 같습니다. 정상 자격 증명으로 들어오는 경우가 취약점을 악용하는 경우보다 많습니다. 재설정 기능은 서비스가 자기 공식 절차로 그 자격 증명을 발급하는 곳입니다.
나타나는 5가지 형태
- 1. 추측 가능한 토큰
- 연속된 값, 타임스탬프, 짧은 문자열, 암호학적이지 않은 난수. 추측이나 무차별 대입으로 남의 재설정을 완료할 수 있다
- 2. 죽지 않는 토큰
- 만료 없음, 사용 후에도 유효, 재사용 가능. 한 번 발급된 링크가 무기한 작동한다
- 3. 메일함에 남는 링크
- 메일함을 읽을 수 있는 사람은 재설정 링크도 읽을 수 있다. 전달 규칙, 공용 계정, 퇴사자의 메일함 — 메일은 생각보다 많은 사람이 본다
- 4. 외부에서 정해지는 목적지
- 요청의
Host헤더로 재설정 URL을 만들면, 외부에서 넣은 값이 메일 속 링크가 될 수 있다(Host 헤더 인젝션) - 5. 계정을 드러내는 응답
- 친절한 "등록되지 않음" 메시지나 응답 시간의 차이가 폼을 누가 계정을 갖고 있는지 외부에서 확인하는 수단으로 만든다(사용자 열거)
CWE-640 "Weak Password Recovery Mechanism for Forgotten Password"가 이 유형의 이름입니다. 정의는 제품이 사용자가 원래 비밀번호를 모른 채 비밀번호를 복구하거나 변경할 수 있는 장치를 갖고 있지만, 그 장치가 약한 경우입니다. 요점은 이것입니다. 기능이 있는 것이 문제가 아니라, 그 기능이 대신할 수 있는 인증만큼 강하지 않은 것이 문제입니다.
비밀 질문을 유일한 경로로 쓰지 마라
OWASP는 비밀 질문에 대해, 답을 쉽게 추측하거나 공격자가 손에 넣을 수 있는 경우가 많으므로 비밀번호 재설정의 유일한 수단으로 써서는 안 된다는 입장입니다. 다른 방법과 함께 쓰면 추가 계층이 될 수는 있다고 덧붙입니다. SNS 프로필과 공개 기록이 넘치는 시대에 어머니의 결혼 전 성은 비밀이 아닙니다.
가이드가 요구하는 것과 직접 정해야 하는 것
구현할 때 망설이는 부분이 여기입니다. 둘을 구분하세요.
OWASP가 명시한 것
・토큰은 암호학적으로 안전한 난수 생성기로 만든다
・무차별 대입을 견딜 만큼 길게 한다
・사용 후 무효화한다
・계정이 있을 때와 없을 때 같은 메시지를 반환한다
・열거를 막기 위해 응답 시간도 일정하게 한다
・자동 제출에 대해 요청 횟수 제한, CAPTCHA 등을 쓴다
・기존 세션을 무효화한다(자동으로, 또는 사용자에게 묻는다)
・비밀번호가 재설정되었다고 사용자에게 메일로 알린다. 메일에 비밀번호는 넣지 않는다
・재설정 URL을 만들 때 Host 헤더에 의존하지 않는다(고정값으로 두거나, 신뢰하는 도메인 목록으로 검증)
・URL은 HTTPS를 쓴다
가이드가 정하지 않은 숫자(직접 정한다)
・실제 토큰 길이 — "충분히 길게"라고만 되어 있다
・만료 시간 — 사용 시 무효화는 필수지만, 시간 제한의 숫자는 없다
숫자가 없다는 것을 "정하지 않아도 된다"로 읽지 마세요. 이유를 갖고 정하고, 기록해 둬야 합니다.
본 사이트의 실무 기본값: URL에 안전한 인코딩으로 128비트 이상의 무작위성, 수십 분 단위의 만료, 사용 시 무효화, 같은 계정에 새 토큰을 발급하면 이전 토큰도 무효화. 숫자보다 세 가지 성질이 중요합니다. 추측할 수 없고, 재사용할 수 없고, 영원히 살아 있지 않을 것.
구현 순서
토큰을 추측할 수 없게 한다(최우선)
암호학적 난수로 만들고 URL에 안전하게 인코딩합니다. 범용 난수 함수는 쓰지 마세요. "무작위로 보인다"와 "예측할 수 없다"는 다른 성질입니다. 토큰 자체가 아니라 토큰의 해시를 저장해서, 데이터베이스를 읽을 수 있게 되더라도 바로 쓸 수 있는 토큰이 나오지 않게 합니다(비밀번호 저장, 해시와 솔트와 같은 이유입니다).
수명을 주고, 한 번만 쓰게 한다
사용하면 무효화하고, 시간이 지나도 만료시킵니다. 같은 계정에 새 토큰을 발급하면 이전 토큰도 무효화하세요. 이것을 잊으면 형태 2로 돌아갑니다.
URL을 외부 입력으로 만들지 않는다
재설정 링크는 설정값으로 만들거나, 신뢰하는 도메인 목록으로 검증합니다. 요청 헤더를 그대로 메일에 넘기지 마세요. OWASP가 직접 지목하는 항목입니다.
응답을 똑같이 하고, 요청 횟수를 제한한다
어느 경우든 같은 문구와 같은 시간으로 응답하고, 실제로 계정이 있을 때만 메일을 보냅니다. 자동 제출에 대비해 계정별 요청 횟수 제한이나 CAPTCHA를 추가합니다. 사용자는 불편하지 않고, 외부에서는 두 경우를 구분할 수 없습니다.
완료 시 마무리까지 한다
재설정이 완료되면 기존 세션을 무효화합니다. 계정이 이미 탈취된 상태라면 공격자를 쫓아낼 유일한 방법입니다. 그리고 비밀번호가 재설정되었다는 알림을 보냅니다(비밀번호는 넣지 않음). 가능하면 재설정 경로에서도 두 번째 인증 요소를 요구해, 재설정이 다중 인증을 우회하는 길이 되지 않게 합니다.
재설정이 실제로 의존하는 것은 메일함이다
위의 것을 모두 해도, 재설정의 안전은 결국 계정 주인만 그 메일을 받을 수 있느냐에 달려 있습니다. 이메일 계정이 탈취되면, 잘 만든 재설정 기능일수록 오히려 확실하게 계정을 공격자에게 넘깁니다. 그래서 사용자 쪽 우선순위도 같은 곳으로 모입니다. 이메일 계정을 가장 강하게 보호하세요. 고유하고 강한 비밀번호와 다중 인증, 가능하면 패스키를 쓰세요. 이것은 서비스 제공자 쪽의 침해가 나에게 번지는 경로이기도 합니다(호스팅 업체가 침해되었을 때 할 일).
사용자 쪽에서 보면
- 요청하지 않은 재설정 메일은 누군가 시도했다는 알림입니다. 링크를 누르지 말고 직접 그 서비스에 로그인해서 확인하세요(피싱도 똑같은 모습으로 옵니다).
- 재설정 후 다른 기기에서 로그아웃되는 것은 올바른 구현의 신호입니다. 재설정 후에도 다른 세션을 살려 두는 서비스에서는 침입자를 끊어 낼 방법이 없습니다.
- 재설정 중에 두 번째 요소를 묻지 않는다면, 그 서비스에서는 그 경로로 다중 인증을 우회할 수 있을지 모릅니다. 중요한 계정은 한 번 확인해 볼 만합니다.
- 비밀번호 재사용을 끝내는 일은 비밀번호 관리자에게 맡기는 것이 가장 좋습니다.
본 사이트의 견해: 편의 기능이 아니라 인증으로 만들어라
재설정 기능이 약해지는 것은 기술적으로 어려워서가 아니라 엉뚱한 분류에 들어가기 때문입니다. 로그인은 인증 담당자가 신중하게 만들고, "비밀번호를 잊으셨나요?"는 지원용 경로로 가볍게 만들어집니다. 이 취급의 차이가 약점입니다. 본 사이트의 입장은 단순합니다. 계정의 통제권을 넘기는 모든 작업은 인증 기능입니다. 재설정, 이메일 주소 변경, 두 번째 요소 재등록, 고객 지원 담당자의 수동 복구 모두 그렇습니다. 강도는 가장 강한 경로가 아니라 가장 약한 경로가 정합니다. 자기 서비스에서 계정에 닿는 경로를 모두 적어 보세요. 대개 생각보다 많습니다.
출처(공식)
- OWASP Cheat Sheet Series, "Forgot Password Cheat Sheet" — cheatsheetseries.owasp.org (위에서 "명시한 것"으로 든 요구 사항은 모두 이 문서에서 나왔습니다. 토큰 길이와 만료 시간은 정하고 있지 않습니다)
- MITRE, CWE-640 "Weak Password Recovery Mechanism for Forgotten Password" — cwe.mitre.org
다음으로 읽기
- 방어: 비밀번호 관리자 고르는 법과 쓰는 법 / 비밀번호 저장, 해시와 솔트
- 용어: 2단계 인증이란 / 패스키란 / 피싱이란
- 남용 대책: 요청 횟수 제한과 남용 대책 (재설정 경로의 횟수 제한을 어디에 둘까)
- 경향: 2026년, 공격자는 취약점보다 자격 증명으로 더 자주 들어왔다
FAQ
Q다중 인증을 켜 두었다면, 비밀번호 재설정이 약해도 괜찮지 않나요?
괜찮지 않습니다. 재설정 경로에서 두 번째 인증 요소를 요구하지 않는 구현이 많고, 그런 경우 재설정은 두 번째 요소를 피해 계정을 되찾는 방법이 됩니다. 지켜야 하는 것은 로그인 화면의 강도가 아니라 계정에 닿는 모든 경로의 강도입니다. 재설정이 끝나면 기존 세션을 무효화하고, 가능하면 재설정 경로에서도 두 번째 요소를 요구하세요.
Q재설정 토큰은 얼마나 길게, 얼마 동안 유효하게 해야 하나요?
OWASP Forgot Password Cheat Sheet는 토큰을 암호학적으로 안전한 난수 생성기로 만들고, 무차별 대입을 견딜 만큼 길게 하고, 사용 후 무효화해야 한다고 하지만, 글자 수나 분 단위 숫자는 정하지 않습니다. 그 숫자는 직접 정해야 합니다. 본 사이트의 실무 기본값은 URL에 안전한 인코딩으로 128비트 이상의 무작위성, 수십 분 단위의 만료, 사용 시 무효화, 같은 계정에 새 토큰을 발급하면 이전 토큰도 무효화입니다. 숫자보다 중요한 것은 세 가지 성질입니다. 추측할 수 없고, 재사용할 수 없고, 영원히 살아 있지 않을 것.
Q'등록되지 않은 이메일 주소입니다'라고 알려 주는 게 친절하지 않나요?
사용자에게는 친절하지만, 공격자에게는 어떤 주소가 그 서비스에 계정을 갖고 있는지 공짜로 확인하는 방법이 됩니다. OWASP는 계정이 있을 때와 없을 때 같은 메시지를 보여 주고, 응답 시간도 일정하게 하라고 요구합니다. 어느 경우든 같은 화면을 보여 주고, 실제로 계정이 있을 때만 메일을 보내세요. 사용자는 불편하지 않고, 외부에서는 차이가 보이지 않습니다.
Q사용자로서는 무엇을 할 수 있나요?
요청하지 않은 재설정 메일은 누군가 내 계정을 재설정하려 했다는 알림입니다. 링크를 누르지 말고 직접 그 서비스에 로그인해서, 비밀번호를 다른 곳에 재사용하고 있지 않은지, 다중 인증이 켜져 있는지 확인하세요. 그리고 재설정이 실제로 무엇에 의존하는지 기억하세요. 바로 메일함입니다. 누군가 내 이메일을 읽을 수 있다면 여러 계정의 비밀번호를 줄줄이 재설정할 수 있습니다. 이메일 계정을 가장 강하게 보호하세요.