Sumin

공부하는 중

Lecture/보안프로토콜

OTP 구현과 실행결과

sum1n52 2026. 3. 20. 22:30

OTP란?

OTP (One-Time Password, 일회용 비밀번호)는 한 번만 사용할 수 있는 비밀번호로, 사용자 인증 과정에서 보안을 강화하기 위해 사용된다. 일반적인 고정 비밀번호는 유출될 경우 반복적으로 악용될 수 있지만, OTP는 매번 새로운 값이 생성되기 때문에 보안성이 높다.

OTP는 인터넷 뱅킹, 로그인 인증, 결제 시스템 등 다양한 분야에서 활용하고 있으며, 대표적인 방식으로는 시간 동기화 방식 (TOTP), 이벤트 동기화 방식 (HOTP), 그리고 챌린지-응답 방식이 있다.

 


 

시간 동기화 방식

 

시간 동기화 방식은 현재 시간을 기준으로 OTP를 생성하는 방식이다.

 

사용자와 서버는 동일한 비밀키를 공유하고 있으며, 동일한 시간 값을 입력으로 사용하여 같은 OTP를 생성한다. 이 방식은 일정 시간 (보통 30초)마다 OTP가 자동으로 변경되며, 시간이 지나면 이전 OTP는 사용할 수 없게 된다.

따라서 서버와 클라이언트 간의 시간이 정확하게 동기화되어 있어야 하며, 이러한 특성 덕분에 높은 보안성을 제공한다. 이 방식은 대표적으로 Google OTP와 같은 인증 시스템에서 널리 사용된다.

 

 

TOTP Python 구현

import pyotp

# 1. 비밀키 생성
secret = pyotp.random_base32()
print("비밀키:", secret)

# 2. TOTP 객체 생성
totp = pyotp.TOTP(secret)

# 3. OTP 생성
otp = totp.now()
print("현재 OTP:", otp)

# 4. OTP 검증
result = totp.verify(otp)
print("검증 결과:", result)

 

실행 결과

비밀키: 7X3F2RLALZIVRA7HMEUGAHJK4LADXNQP
현재 OTP: 607259
검증 결과: True

 

pyotp 라이브러리를 사용하였고, pyotp.random_base32() 함수는 OTP 생성에 사용되는 비밀키를 생성하며, pyotp.TOTP(secret)은 해당 비밀키를 기반으로 TOTP 객체를 생성한다. 이후 now() 함수를 통해 현재 시간을 기준으로 OTP를 생성하고, verify() 함수를 이용하여 생성된 OTP의 유효성을 검증한다.

 

TOTP JavaScript 구현

const crypto = require('crypto')

function generateTOTP(secret) {
  const time = Math.floor(Date.now() / 30000) // 30초 단위

  const hmac = crypto.createHmac('sha1', secret)
  hmac.update(time.toString())

  const hash = hmac.digest('hex')

  return hash.substring(0, 6) // 6자리 OTP
}

const secret = 'MYSECRETKEY'

const otp = generateTOTP(secret)
console.log('OTP:', otp)

 

실행 결과

OTP: 6703d7

 

별도의 라이브러리 없이 crypto 모듈을 사용하여 구현하였다. crypto.createHmac() 함수로 HAMC 해시 객체를 생성하고, update() 함수로 시간 값을 입력한 뒤 digest('hex')를 통해 해시 결과를 생성하여 OTP를 만든다.

 


 

이벤트 동기화 방식

 

이벤트 동기화 방식은 카운터 값을 기반으로 OTP를 생성하는 방식이다.

 

OTP가 생성될 때마다 카운터 값이 1씩 증가하며, 서버와 사용자 측은 동일한 카운터 값을 유지해야 한다. 사용자가 버튼을 누르거나 인증을 시도할 때마다 새로운 OTP가 생성되며, 시간과는 관계없이 동작한다.

따라서 카운터 값이 매우 중요한 요소이며, 서버와 사용자 간의 카운터 값이 일치하지 않을 경우 인증에 실패할 수 있다.

 

 

HOTP Python 구현

import hmac
import hashlib

secret = b"MYSECRETKEY"
counter = 1  # 버튼 누를 때마다 증가

def generate_hotp(secret, counter):
    counter_bytes = counter.to_bytes(8, 'big')
    hmac_hash = hmac.new(secret, counter_bytes, hashlib.sha1).hexdigest()
    return hmac_hash[:6]

otp = generate_hotp(secret, counter)
print("HOTP:", otp)

 

실행 결과

HOTP: a80f24

 

HAMC-SHA1 알고리즘을 사용하여 구현하였고, hmac.new() 함수를 사용하여 비밀키와 카운터 값을 기반으로 해시를 생성하며, 이 때 to_bytes() 함수를 통해 카운터 값을 바이트 형태로 변환한다. 이후 hexdigest()를 이용하여 결과를 문자열로 출력한다.

 

HOTP JavaScript 구현

const crypto = require('crypto')

function generateHOTP(secret, counter) {
  const counterBuffer = Buffer.alloc(8)
  counterBuffer.writeUInt32BE(counter, 4)

  const hmac = crypto.createHmac('sha1', secret)
  hmac.update(counterBuffer)

  const hash = hmac.digest('hex')

  return hash.substring(0, 6)
}

const secret = 'MYSECRETKEY'
const counter = 1

const otp = generateHOTP(secret, counter)
console.log('HOTP:', otp)

 

실행 결과

HOTP: a80f24

 

Python과 동일하게 HMCA-SHA1 알고리즘을 사용하여 구현하였으며, Buffer.alloc()을 사용하여 카운터를 바이트 배열로 생성하고, writeUInt32BE()를 통해 값을 저장한다. 이후 crypto.createHmac()을 사용하여 해시를 생성하고 OTP를 도출한다.

 


 

챌린지-응답 방식

 

챌린지-응답 방식은 서버가 사용자에게 임의의 값인 챌린지 (Challenge)를 제공하면, 사용자는 이를 바탕으로 응답 (Response)을 생성하는 방식이다.

 

이 과정에서 사용자와 서버가 공유하고 있는 비밀키가 사용되며, 동일한 챌린지 값에 대해서는 항상 동일한 응답이 생성된다.

매번 서로 다른 챌린지가 사용되기 때문에 보안성이 높으며, 서버와 사용자 간의 상호작용이 필요하다는 특징이 있다.

 

 

챌린지-응답 Python 구현

import hmac
import hashlib

secret = b"MYSECRETKEY"
challenge = b"RANDOM_CHALLENGE"

def generate_response(secret, challenge):
    hmac_hash = hmac.new(secret, challenge, hashlib.sha256).hexdigest()
    return hmac_hash[:8]

response = generate_response(secret, challenge)
print("Response:", response)

 

실행 결과

Response: 708fd1f6

 

서버로부터 전달받은 challenge 값을 이용하여 응답을 생성한다. hmac.new()과 hashlib.sha256을 사용하여 비밀키와 challenge 값을 결합한 해시를 생성하며, hexdigest()로 결과를 출력한다.

 

챌린지-응답 JavaScript 구현

const crypto = require('crypto')

function generateResponse(secret, challenge) {
  const hmac = crypto.createHmac('sha256', secret)
  hmac.update(challenge)

  const hash = hmac.digest('hex')

  return hash.substring(0, 8)
}

const secret = 'MYSECRETKEY'
const challenge = 'RANDOM_CHALLENGE'

const response = generateResponse(secret, challenge)
console.log('Response:', response)

 

실행 결과

Response: 708fd1f6

 

Python과 동일하게 서버로부터 전달받은 challenge 값을 이용하여 응답을 생성한다. crypto.createHmac()을 사용하여 동일한 방식으로 해시를 생성하고, update()와 diges('hex')를 통해 최종 응답값을 생성한다.

 


 

OTP의 장점

OTP는 매번 새로운 비밀번호를 생성하여 기존의 고정 비밀번호보다 훨씬 높은 보안성을 제공하는 인증 방식이다. 일반적인 비밀번호는 한 번 유출될 경우 반복적으로 악용될 수 있지만, OTP는 한 번 사용된 값은 다시 사용할 수 없기 때문에 이러한 위험을 크게 줄일 수 있다. 특히 네트워크 환경에서 발생할 수 있는 도청이나 해킹 공격에 대해서도 비교적 안전한 인증 수단으로 활용될 수 있다.

 

시간 동기화 방식 (TOTP)은 현재 시간을 기준으로 OTP를 생성하기 때문에 사용이 간편하고 별도의 입력 없이 자동으로 값이 변경되어 사용자 편의성이 높다. 이벤트 동기화 방식 (HOTP)은 카운터 값을 기반으로 동작하여 시간에 영향을 받지 않는다는 장점이 있으며, 특정 이벤트가 발생할 때마다 OTP를 생성할 수 있어 다양한 환경에서 유용하게 활용될 수 있다. 챌린지-응답 방식은 서버와 사용자 간의 상호작용을 통해 인증이 이루어지며, 매번 다른 challenge 값을 사용하기 때문에 보안성이 매우 높은 방식이다.

 

이처럼 OTP는 다양한 방식으로 구현될 수 있으며, 각 방식은 사용 환경과 목적에 따라 적절하게 선택될 수 있다. 실제로 금융 서비스, 온라인 계정 보안, 이중 인증 (2FA) 등 다양한 분야에서 OTP가 널리 사용되고 있으며, 안전한 사용자 인증을 위한 핵심 기술로 자리잡고 있다.

'Lecture > 보안프로토콜' 카테고리의 다른 글

기말고사 과제  (0) 2026.05.31
HTTPS 표준 프로토콜 분석 보고서  (0) 2026.05.20
중간고사 프로젝트 과제  (0) 2026.04.21
중간고사 조사 과제  (0) 2026.04.17