TOTP 코드의 작동 원리

TOTP 코드는 인증 앱과 서버가 각각 독립적으로 계산하는 6자리 숫자입니다. 입력은 단 두 가지, 공유 비밀키와 30초 윈도우로 나눈 현재 시각입니다. 코드 자체는 설정 과정에서 전송되지 않으며 비밀키에 대한 어떤 정보도 담지 않지만, 양쪽은 같은 숫자에 도달합니다. TOTP는 마법도 무작위성도 아니라, 공개된 알고리즘(RFC 6238)을 같은 입력에 적용한 결과이기 때문입니다. 이 글은 계산을 처음부터 끝까지 따라가고, "잘못된 코드"가 거의 항상 시계 문제인 이유를 설명하며, 두 번째 요소가 두 번째 요소로 남는지를 결정하는 취급 규칙을 다룹니다. 모든 단계를 브라우저에서 로컬로 코드를 계산하는 TOTP 생성기에서 직접 실행해 볼 수 있습니다.

두 가지 입력, 하나의 코드: 비밀키와 시계

2단계 인증을 켜면 서비스는 무작위 비밀키를 생성합니다. 보통 20바이트이며, Base32 문자열로 보여 주고 편의를 위해 QR 코드에도 인코딩됩니다. 이 비밀키가 저장되는 곳은 정확히 두 곳, 서비스의 데이터베이스와 당신의 인증 앱입니다. 그 순간부터 로그인은 동기화된 계산이 됩니다. 양쪽이 현재 Unix 시간을 가져와 시간 단계(거의 모든 서비스에서 30초)로 나누고, 도출된 카운터를 비밀키와 함께 해시 함수에 넣습니다. 일치하는 출력을 제시한 쪽이 비밀키 보유자로 취급됩니다.

이 설계의 우아함은 무엇을 빼놓았는지에 있습니다. 보낼 챌린지도, 전달할 코드도, 네트워크 왕복도, 로그인마다 가로챌 것도 없습니다. "일회용"이라는 속성은 시계에서 옵니다. 카운터가 30초마다 바뀌고 오래된 출력은 가치가 없어지기 때문입니다. 또한 잘못될 수 있는 것이 정확히 두 가지뿐이라는 뜻이기도 합니다. 비밀키와 시간입니다. 거의 모든 TOTP 실패와 모든 TOTP 도난은 이 둘 중 하나로 거슬러 올라갑니다.

계산, 단계별로

카운터는 먼저 8바이트 빅엔디언 정수로 기록됩니다. 양쪽이 합의한 고정 너비 인코딩입니다. 그다음 그 메시지는 비밀키를 키로 사용하는 HMAC을 통과합니다. 사용하는 해시는 합의된 것으로, 기본값은 SHA-1이며 선택하는 서비스를 위해 SHA-256과 SHA-512도 정의되어 있습니다. HMAC은 키가 있는 구조이지 단순한 해시가 아닙니다. 카운터만 해시하면 알고리즘을 아는 누구나 코드를 재현할 수 있지만, HMAC 출력은 비밀키 없이는 위조할 수 없고 역으로 돌려 비밀키를 복구할 수도 없습니다.

다이제스트는 20바이트 이상이지만 로그인 칸이 원하는 것은 6자리입니다. 그 다리가 동적 절단입니다. 다이제스트의 마지막 반 바이트가 오프셋을 선택하고, 그 오프셋에서 4바이트를 읽어 최상위 비트를 마스킹한 뒤(부호 모호성을 피하기 위해), 도출된 31비트 수를 10의 자릿수 거듭제곱으로 나눈 나머지로 줄입니다(표준 6자리는 백만). 왼쪽은 0으로 채웁니다. 그것이 당신이 입력하는 코드입니다. 다음 윈도우는 처음부터 다시 계산합니다. 코드들을 잇는 사슬은 없으므로, 사진으로 찍은 코드는 30초 뒤에는 가치가 없습니다.

코드가 거부될 때: 대개는 시계 탓

카운터는 시간에서 도출되므로, 생성기와 서버는 현재의 30초 윈도우가 무엇인지에 동의해야 합니다. 대부분의 서버는 이를 완화해 이웃한 윈도우도 받아들입니다(양쪽으로 한 단계씩). 작은 오차는 조용히 흡수됩니다. 그 범위를 벗어나면 비밀키가 아무리 정확해도 모든 코드가 틀리고, 실패의 모습은 숫자를 잘못 입력한 것과 똑같습니다. 어떤 입력이 어긋났는지에 대한 힌트도 없이 단호하게 거부됩니다.

그래서 갑자기 작동을 멈춘 인증 앱의 첫 번째 진단은 결코 비밀키가 아닙니다. 코드를 생성하는 기기의 시계입니다. 수동으로 설정한 시간, 다 죽어 가는 CMOS 배터리, 비행 내내 잘못된 시간대 모드에 있던 휴대폰, 어느 것이든 기기를 1분 이상 어긋나게 할 수 있습니다. 우리 TOTP 생성기가 실시간 시계 카드를 보여주고 당신의 기기를 서버 시간과 비교하는 것은 바로 이 때문입니다. 자동 날짜 및 시간을 켜면 코드는 거의 항상 다시 작동합니다. 초기화도, 새 비밀키도, 지원 티켓도 필요 없습니다.

비밀키가 전부다

의식을 걷어내면 TOTP 보안은 하나의 사실로 귀결됩니다. 비밀키를 가진 자는 두 번째 요소를 영원히, 어디에서든 가지며, 서비스는 그 코드를 당신의 코드와 구별할 수 없습니다. 설정 때 스캔하는 QR 코드는 코드의 그림이 아닙니다. 그것은 비밀키 자체에 계정 레이블과 매개변수를 더해 otpauth:// URI로 형식화한 것입니다. 그 스크린샷은 당신의 두 번째 요소의 영구적인 사본입니다.

그래서 취급 규칙은 비밀번호보다 더 엄격합니다. 비밀번호는 서버가 검증하고 해시로 저장할 수 있지만, TOTP 비밀키는 양쪽이 원형 그대로 꺼낼 수 있어야 하므로 해시로 녹여 버릴 수 없으며, 모든 사본이 살아 있는 사본입니다. 마스터 사본은 인증 앱이나 암호화된 비밀번호 관리자에 보관하세요. 서버에서 코드를 생성하는 웹사이트에 절대로 입력하지 마세요. 낯선 이에게 영구적인 열쇠를 건넨 셈입니다. 그리고 절대로 채팅에 붙여 넣지 마세요. 그 이유는 다음 섹션에서 설명합니다.

비밀키를 절대 채팅에 넣어서는 안 되는 이유

2FA 비밀키를 채팅(지원 대화, 팀 채널, AI 어시스턴트)에 붙여 넣는 것은 무해해 보입니다. 문자열은 횡설수설처럼 보이고 대화는 사적으로 느껴지기 때문입니다. 하지만 둘 다 아닙니다. 채팅은 기록되고, 보존되고, 계정의 모든 기기에 동기화되고, 검색 가능하며, 당신이 통제하지 않는 서버에서 처리됩니다. AI 채팅은 여기에 학습 파이프라인과 장기 보존까지 더합니다. 비밀키가 거기에 도착하는 순간, 당신의 두 번째 요소는 텍스트를 저장하고 색인하도록 설계된 시스템 안에 존재하게 됩니다.

안전한 패턴은 비밀키가 존재해야 할 장소가 세 종류뿐이라는 것입니다. 서비스의 데이터베이스, 당신의 인증 앱이나 비밀번호 관리자, 그리고 당신이 통제하는 기기에서의 로컬 계산. 이 사이트의 TOTP 생성기가 바로 그렇게 만들어졌습니다. 비밀키는 페이지 메모리에만 보관되고 새로고침하면 파기됩니다. 비밀키를 이미 붙여 넣지 말아야 할 곳에 붙여 넣었다면, 태워진 것으로 취급하세요. 서비스에서 2단계 인증을 껐다가 다시 켜서 새 비밀키를 발급하고, 인증 앱을 다시 등록하고, 그 김에 비밀번호 자체를 비밀번호 유출 확인에서 점검하세요.

TOTP가 막지 못하는 것

TOTP는 비밀번호 도난, 크리덴셜 스터핑, 데이터베이스 유출을 무너뜨립니다. 비밀번호를 아는 것만으로는 더 이상 충분하지 않습니다. 그러나 실시간 피싱은 무너뜨리지 못합니다. 당신의 자격 증명을 실제 서비스로 중계하고 코드를 요구하는 가짜 로그인 페이지는 그 30초 윈도우 안에 코드를 그대로 전달할 수 있습니다. 코드는 비밀키의 보유를 증명할 뿐, 진짜 사이트와 대화하고 있음을 증명하지 않기 때문입니다. 세션 쿠키 도난도 이를 똑같이 완전히 우회합니다. 코드는 한 번만 검사되기 때문입니다.

그래서 패스키와 하드웨어 보안 키가 최상위 영역에서 TOTP를 대체하고 있습니다. 증명을 사이트의 출처에 묶어, 중계자가 훔칠 수 있는 입력 가능한 것을 아무것도 남기지 않기 때문입니다. TOTP는 여전히 강력하고 보편적인 기준선이며, 전화망의 약점을 물려받는 SMS 코드보다 훨씬 낫습니다. 하지만 눈을 뜨고 도입해야 합니다. 비밀키를 마스터 키처럼 보호하고, 백업 코드는 별도의 장소에 보관하고, 시계를 정직하게 유지하고, 서비스가 제공하는 곳에서는 패스키를 우선하세요.

출처

자주 묻는 질문

내 코드에서 비밀키를 도출할 수 있나요?

아니요. 각 코드는 절단된 HMAC 출력이며, HMAC은 단방향 구조입니다. 아무리 많은 코드를 관찰해도 공격자는 키를 재구성할 수 없고, 키 없이 미래 윈도우의 코드를 예측할 수도 없습니다. 두 번째 요소가 실제로 도난당하는 경로는 비밀키 자체의 유출(스크린샷, 채팅, 서버 측 생성기)과 윈도우 안에서 신선한 코드를 중계하는 실시간 피싱입니다.

서비스는 왜 이전 코드와 다음 코드도 받아들이나요?

관용 때문입니다. 당신의 기기와 서버가 윈도우가 바뀌는 정확한 초에 동의하는 경우는 드물고, 작은 시계 오차는 흔하므로, 대부분의 서버는 이웃한 시간 단계의 코드도 받아들입니다. 이는 유효한 윈도우를 30초에서 대략 90초로 넓히며, 의도적인 사용성 절충입니다. 사진으로 찍은 코드는 1분 뒤에는 여전히 가치가 없습니다.

SHA-1이 "깨졌다"는데, SHA-1 TOTP는 아직 안전한가요?

이 구조에서는 안전합니다. 유명한 SHA-1 공격이 깨는 것은 충돌 저항성이며, 그것은 서명과 인증서에서 중요합니다. HMAC의 보안은 충돌 저항성에 기대지 않습니다. 키가 있는 구조가 의사난수 함수처럼 동작하는 데 기댑니다. 그리고 관찰된 출력에서 TOTP 비밀키를 복구하거나 코드를 위조하는 실용적인 공격은 존재하지 않습니다. 서비스는 그래도 SHA-256을 선택할 수 있으며, 이 사이트의 생성기는 세 가지 모두를 지원합니다.