0 / 5
시간 동기화 방식 (TOTP, Time-based OTP)
고정 비밀번호는 한 번 새어 나가면 누구나 계속 쓸 수 있다. OTP는 로그인할 때마다 번호를 새로 만들어 한 번만 쓴다. 사용자의 OTP 기기와 서버는 같은 비밀키에 매번 바뀌는 값을 섞어 각자 같은 계산을 하고, 두 결과가 같으면 통과시킨다. 방식은 그 바뀌는 값이 무엇이냐로 나뉜다.
바뀌는 값으로 현재 시각을 30초 단위로 잘라 쓴다. 기기와 서버가 같은 시각을 각자 알고 있어서 이 값을 주고받지 않는다. 그래서 동기 방식이다.
예: 은행 OTP 앱에 6자리 번호가 뜨고 30초마다 바뀐다.
1 / 5
사용자: OTP 만들기
지금 시각 09:00:12는 09:00:00부터 시작하는 30초 구간에 속한다. 기기가 이 구간 값과 비밀키 K를 해시 함수에 함께 넣고, 결과를 6자리로 줄여 482 913을 만든다.
2 / 5
사용자 → 서버: 번호 입력
사용자가 기기에 뜬 482 913을 로그인 화면에 입력해 서버로 보낸다. 비밀키 K와 시각은 보내지 않는다.
3 / 5
서버: 같은 계산 하기
서버도 자기 시계로 지금 구간(09:00:00부터)을 구하고, 등록 때 나눠 가진 같은 비밀키 K와 함께 해시 함수에 넣는다. 결과는 482 913이다.
4 / 5
서버: 두 번호 비교
받은 번호와 서버가 계산한 번호가 같아서 로그인을 통과시킨다. 서버는 이 번호를 쓴 것으로 기록해 같은 번호로 다시 로그인하지 못하게 한다.
5 / 5
30초 뒤: 번호가 바뀜
09:00:30이 되면 구간이 바뀌어 기기와 서버가 각자 새 번호 705 261을 계산한다. 그래서 쓰지 않은 번호라도 30초가 지나면 곧 쓸 수 없게 된다. 다만 서버는 입력하는 사이에 구간이 바뀌는 경우를 생각해 바로 앞 구간 하나 정도까지는 받아 준다.
1 / 6
사용자: 버튼 누르기
사용자가 버튼을 누르면 기기 카운터가 6에서 7로 오른다. 기기가 카운터 7과 비밀키 K를 해시 함수에 함께 넣어 159 044를 만든다.
2 / 6
사용자 → 서버: 번호 입력
사용자가 159 044를 로그인 화면에 입력해 보낸다. 카운터와 비밀키 K는 보내지 않는다.
3 / 6
서버: 같은 계산 하기
서버도 이 사용자의 카운터를 따로 세고 있다. 다음 차례인 카운터 7과 같은 비밀키 K로 계산하면 159 044가 나온다.
4 / 6
서버: 두 번호 비교
두 번호가 같아서 통과시킨다. 서버는 인증에 성공했을 때만 자기 카운터를 올린다. 이제 서버가 기다리는 다음 카운터는 8이다.
5 / 6
사용자: 쓰지 않은 번호가 생기면
사용자가 버튼을 두 번 눌러 놓고 그 번호(카운터 8, 9)는 쓰지 않았다. 기기 카운터는 누를 때마다 오르므로, 이번에 누르면 10이 되어 640 372를 만들어 보낸다. 서버는 아직 8을 기다린다.
6 / 6
서버: 앞의 카운터까지 계산해 맞추기
서버 카운터 8로 계산한 번호는 받은 번호와 다르다. 서버는 바로 거부하지 않고 9, 10처럼 정해 둔 개수만큼 앞의 카운터로 계산해 본다. 10에서 같은 번호가 나오므로 통과시키고, 서버 카운터를 기기와 맞춘다(다음은 11). 정해 둔 개수 안에서 맞는 번호가 없으면 거부한다.
1 / 5
서버 → 사용자: 질의값 보여 주기
사용자가 로그인을 시작하면 서버가 임의의 숫자 5831을 새로 만들어 로그인 화면에 보여 준다. 이 숫자가 질의값이다.
2 / 5
사용자: 질의값 입력하고 응답값 만들기
사용자가 화면의 5831을 OTP 기기에 직접 입력한다. 기기는 질의값과 비밀키 K를 해시 함수에 함께 넣어 응답값 273 650을 만든다.
3 / 5
사용자 → 서버: 응답값 입력
사용자가 응답값 273 650을 로그인 화면에 입력해 보낸다. 비밀키 K는 보내지 않는다.
4 / 5
서버: 같은 계산 하기
서버는 방금 자기가 만든 질의값 5831과 같은 비밀키 K로 계산해 273 650을 얻는다.
5 / 5
서버: 두 번호 비교
두 번호가 같아서 통과시킨다. 다음 로그인 때는 서버가 새 질의값을 만들기 때문에 이번 응답값은 다시 쓸 수 없다.