나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2024-11-14 11:20:39

RFC 6238

1. 개요2. 방식3. 보안4. 사용5. 지원 사이트 및 앱
5.1. 국내
6. OTP 앱

1. 개요

공식 문서
OTP의 일종인 TOTP(시간 기반 OTP)에 관한 국제 인터넷 표준화 기구(IETF) 표준으로, 현재 많은 웹사이트에서 사용하고 있는 TOTP 방식이다.

2. 방식

RFC 6238은 HMAC-SHA-1 기반 알고리즘으로, HOTP(HMAC 기반 OTP, RFC 4226)의 확장으로 본다. RFC 4226은 Counter 값이 있어 횟수를 기반으로 하는 알고리즘이지만, RFC 6238은 시간을 고유한 값으로 사용한다는 차이점이 있다.

TOTP의 기반이 되는 알고리즘으로서 HMAC-SHA-1 값을 HOTP 값으로 변환하는 Truncate() 함수와[1] secret 값인 K, counter 값인 C로 구성된 HOTP는 다음과 같이 정의된다.
#!syntax java
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

위 식에서 C를 T로 대체하면 TOTP가 된다. 즉, 다음과 같다.
#!syntax java
TOTP = HOTP(K,T)

그러나 TOTP를 구현하기 위해서는 몇 가지 조건이 필요한데, 위 식의 T값을 구하기 위해 증명자(OTP를 입력하는 사람)와 검증자(OTP를 검증하는 사람) 모두가 유닉스 시간을 알고 있어야 한다. 또한 동일한 K값을 서로 가지고 있어야 하며, 동일한 타임스텝 값 X를 사용하고 키 값은 HMAC 출력 길이로 무작위 생성되어야 한다. 그리고 당연한 소리지만 키는 승인되지 않은 접근으로부터 보호받는 곳에 저장되어야 한다.

증명자와 검증자 간에 서로 공유해야 하는 시스템 파라미터로 X와 T0이 있는데, 타임스텝 값인 X는 TOTP의 생성 주기의 초 단위 값을 의미하며, 기본값은 30초이다[2]. 또 다른 변수 T0은 타임스텝의 계산이 시작되는 유닉스 시간 값이다. 이 값은 현재 타임스탬프보다 작은 값으로 한다.

TOTP에서 가장 중요한 부분이라 할 수 있는 T의 값은 현재의 유닉스 시간을 t라 할 때 다음과 같다:
[math(\lfloor T = \dfrac{t - T0}{X} \rfloor)]
만약 2038년 이후에도 이 알고리즘을 지원하려는 경우 T값은 32비트 정수보다 클 수 있어야 한다. 이 식에 따라 T의 값은 타임스텝인 X초마다 1씩 증가하며, 따라서 T값이 증가한 이후 X초동안은 T값이 일정하게 유지되므로 생성되는 OTP의 값도 일정해진다. 따라서 검증자는 동일한 T값이 나오는 시간 범위 안에서는 정확히 몇 초에 OTP값이 생성되었는지까지 알 수는 없다.

한편, T의 값이 변하는 시점에 OTP를 입력했을 경우, 혹은 증명자의 기기와 검증자의 서버 사이의 시간 오차로 인하여 입력 당시의 T값과 검증 당시의 T값이 서로 달라서 검증에 실패할 수도 있다. 그래서 검증자는 이를 충분히 고려하여 증명자의 OTP로부터 도출된 T값이 검증 당시의 T값보다 작은 경우에도 검증에 성공한 것으로 처리할 수 있다. 다만 이 허용 오차 범위가 너무 커진다면 공격에 취약해지므로[3], 보통은 X의 기본값인 30초 정도로 고려해서 T값의 오차는 1까지만 허용한다.[4] 이렇게 하면 수신된 OTP에 대해 (T값 오차범위) + 1번의 검사가 이루어진다. 이외의 보정 방법으로는 NTP를 이용해 시간을 동기화시키는 방법이 있다.

그리고 OTP인 만큼 1회성이어서[5], 마지막 인증 시점과 T값이 달라질 때까지 기다려서 새로운 OTP를 받아야 그 다음 번 인증을 통과할 수 있다.

3. 보안

HOTP 기반 알고리즘인 만큼 HOTP 알고리즘의 보안 강도에 기반하며, 현재로서 이 알고리즘에 대한 최상의 공격법은 무차별 대입이라고 한다. 하지만 일각에서는 취약한 부분이 있다며 문제를 제기하고 있다.

첫째로는 secret 값의 유출가능성으로, OTP 생성의 매개변수가 되는 secret 값이 유출되면 제3자가 OTP를 알아내 2단계 인증이 무력화될 수 있다. 보통 TOTP를 인증기에 등록할 때 QR코드를 스캔하거나 secret 문자열을 입력하는데, 이것이 안전한 방법으로 전달되는 것이 아니라 보통은 웹 페이지에 그대로 출력하는 방식이기 때문에 유출의 위험이 있다고 볼 수 있다. 더군다나 이 값을 토대로 OTP를 생성하기 때문에 secret 값을 암호화하여 제공하는 것은 불가능하다.

둘째로는 해당 secret 문자열 내지는 QR코드를 가지고 있는 한 인증기에 무한정 등록할 수 있다는 것이다. 물론 RFC 6238 표준에서는 하나의 secret은 하나의 기기에만 등록해야 한다고 하고 있지만, 그것을 강제할 방법이 없다는 것이 문제이다.

셋째로는 OTP 앱의 신뢰가능성이다. 현재 TOTP 앱으로 가장 많이 쓰이는 Google Authenticator는, Cerberus라는 신종 트로이목마에 의해 OTP가 해킹당하는 수모를 겪기도 했다.# 이런 경우 외에 앱 내부에 저장된 secret 값이 유출된다거나 하면 큰 피해가 야기될 수 있으므로 신뢰할 수 없는 OTP 앱을 사용하는 것은 특히 피해야 한다.

4. 사용

증명자는 사전에 제공된 QR 코드나 secret 값을 이용해 TOTP 매개변수를 저장한다. 인증이 요구될 경우 증명자는 해당 매개변수를 통해 생성된 값을 입력하며, 검증자는 이 값이 유효한지 검증한다.

QR코드를 통한 경우, Key Uri Format으로 제공된 텍스트를 QR코드화한 이미지를 제공한다. 여기에는 secret 외에도 username, 발행자 등 다양한 정보를 담을 수 있다. 아니면 secret 값을 BASE32로 제공해 사용자가 직접 입력하여 생성기를 활성화할 수 있다.

5. 지원 사이트 및 앱

5.1. 국내

6. OTP 앱

대부분의 TOTP 앱들은 설치된 휴대폰에 물리적으로 접근하거나 휴대폰을 해킹해서 원격접속을 하지 않는 이상 OTP 복제가 불가능하게끔 되어 있어 안전하며, 보통은 모바일 앱의 시간과 로그인하려는 기기의 시간이 일치해야지만 로그인이 된다. 당연히 두 기기의 시간이 다르면 로그인이 되지 않는다. 이는 전용 앱을 사용하는 경우도 동일.


[1] HMAC 값을 8비트 단위로 쪼개고, 맨 마지막 4비트의 값을 offset으로 하여 해당 offset 위치의 4바이트 값을 가져와서 부호 비트를 제거한 후, 10진수로 변환하여 10의 거듭제곱으로 나눈 나머지를 취한다. 입력의 편의를 위해 6자리에서 9자리 사이의 숫자가 사용된다.[2] 보안과 사용성 사이에서 적절히 타협한 값이라고 한다.[3] 마찬가지의 이유로 X값이 너무 길게 설정되는 것도 좋지 않다.[4] 이렇게 설정하면 최소 31초, 최대 59초의 입력 시간이 확보된다. X * (T값 오차범위) + 1 초 이상 X * (T값 오차범위 + 1) - 1 초 이하이다.[5] 같은 OTP 값을 두 번 승인하지 않도록 검증자의 조치가 필요하다.[6] Google Workspace 로그인 시에만 제공.[7] 백업이 가능해졌더라도, 구글 계정 로그인이 불가능한 상황에 대비해 2단계 인증 백업 코드를 반드시 발급받도록 하자.[8] 최초 이 문제를 발견한 보안 연구원은 구글에서 추가 조치가 있기 전까진 사용자들에게 해당 기능을 사용하지 않길 권장했다.[9] 애초 해당 기능을 도입할 때 당연히 적용했어야 될 암호화를 배제한 채 허술하게 업데이트를 진행한 구글이 이해가 안가는 부분.


파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는
문서의 r184
, 4.3.1번 문단
에서 가져왔습니다. 이전 역사 보러 가기
파일:CC-white.svg 이 문서의 내용 중 전체 또는 일부는 다른 문서에서 가져왔습니다.
[ 펼치기 · 접기 ]
문서의 r184 (이전 역사)
문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)

문서의 r (이전 역사)