Java에서 OTP 인증하기 (w/ Google OTP)

생각보다 간단하다. 생각보다..;

YI Eun Gook
4 min readNov 13, 2018

2FA를 구현할 때 생각하기 편한게 역시 OTP다.
그러면 TOTP를 사용하는 Google OTP(=Google Authenticator)가 바로 생각난다.
여기에는 OTP에 대한 기술적인 부분 보다는 적당한 흐름과 아주 간단한 구현을 공유해두려고 한다.

먼저 TOTP가 뭔지 간단히 위키백과의 관련 문서를 읽고 오자.
그리고 TOTP 인증의 흐름을 같이 보자.

1. 서버는 Key를 만든다.
2. 서버는 사용자에게 아까 만든 Key를 준다.
3. 사용자는 Google OTP에 2의 Key를 등록한다.
4. 사용자는 Key와 현재 시각을 섞어서 일회용 비밀번호를 만든다.
5. 서버도 Key와 현재 시각을 섞어서 일회용 비밀번호를 만든다.
6. 서버는 4와 5의 비밀번호가 같은지 확인한다.
7. 6의 결과에 따라 인증이 성공하거나 실패한다.

이 과정에서 걱정 포인트가 세 개 있다.

A. 우선 1번과 2번의 Key. 당연하지만.. 각 사용자별로 서로 다른 Key를 만들어서 줘야 한다. 아니면 모든 사용자가 같은 TOTP를 사용하게 되고.. 몹시 곤란해진다. 그리고 아아아아주 당연하지만! Key는 서버와 사용자 둘만의 비밀이다.

B. 4번과 5번에서 사용하는 알고리즘은 같다. (HMAC-SHA-1을 사용한다고 한다.) 고로 당연하지만.. 사용자의 시각과 서버의 시각이 서로 같아야 한다는 거다. 이게 좀 많이 중요할 것 같다. 놓치기 쉬울 것 같다. (국외에도 서비스를 한다면.. 혹은 서버가 AWS 등 국외에 있다면..)

C. 그런데 4와 5의 시각이 완전히 동일할 수 있나? 몇 시 몇 분 몇 초 몇 밀리세컨드? 같을 수가 없다 -_-;;; 고로 Google Auth.에서는 30초 단위로 끊어서 한다. (참고로 이걸 time-step이라고 한다.)

그러면 구현해둔걸 한 번 같이 보자.
이 블로그 포스팅의 구현을 조금 정리해둔 정도이다.

<코드가 길어서 1/3씩 끊어서 올립니다.>

먼저 #11을 보면 Apache Commons Codec을 사용했다. 적당히 가져오자.
그럼 이제 main()을 보면 간단히 구조를 알 수 있다.
1, 2는 init()에서, 3, 4는 getCode()에서, 5, 6, 7은 isValidation()에서 한다.
코드를 보면 알지만 정말 별 것 없다.

다만 #27의 scratchCode에 할당된 25byte가 신경 쓰이는데.. 결론부터 말하면 신경 안 써도 된다. 이건 TOTP의 기본 스펙에는 없는 내용으로 ‘스크래치 코드’ 라는 Time-based와 무관하게 비상시에 사용할 수 있는 일회용 비밀번호를 다섯 개 만들어두는 부분인데, 여기서 이 부분은 구현되어 있지 않다. Google Authenticator쪽을 참고해서 모양만 내본 코드였던듯 하다.

<2/3>

사실 isValidation()에는 6, 7만 있고 5는 getHash()에 들어있다.
여기서 포인트는 #8인데, getHash()를 호출하기 전에 [-3..3]의 i를 넣어 보정해주고 있다.

걱정 포인트 C 때문에.. 사용자와 서버의 시각이 어쩌면 다를지도 모른다는 생각에 들어간 보정용 코드이다. 플러스 마이너스 1분 30초의 여유 시간을 준다는 뜻이다. i의 범위는 적당히 조정하거나 필요 없으면 쓰지 말자. 참고로 이걸 window size라고 부른다. (이 코드의 window size는 3+1+3 = 7이 되겠네요)

<3/3>

대망의 getHash() 내용. 5번이 구현되어 있다. 즉 5의 내용은 사실 Google OTP 내부의 내용과 완전히 동일하다는 거다. (그래야 7을 할 수 있겠지..) 정확히 말하자면 RFC 6238의 generateTOTP()을 참고하여 구현한 것. 조금 더 정확히는 RFC 4226을 구현한 것.. 고로 이 부분은 자세한 설명을 패스합니다. (외면 -_-);;;

사실 콘솔에 toBinaryString() 찍어가면서 보면 생각보다 간단한 구조라는게 보인다. 찍어보고 RFC 문서 읽는게 이해가 더 빠를지도..

참고한 문서들

위키백과: 일회용 비밀번호-시간 동기화 방식
블로그: Google Authenticator(Google OTP)를 이용한 개발.
gist: google-authenticator와 관련된 노트
RFC 6238
RFC 4226

--

--

No responses yet