거래소 인증 비교: API Key·HMAC·JWT·토큰 만료
TECH INSIGHT / EXPLAINED
API Key·HMAC·JWT는 서로 배타적인 세 가지 보안 등급이 아닙니다. 한 요청이 헤더의 키로 계정을 식별하면서 서명을 검증할 수 있고 JWT 자체가 HMAC을 사용할 수도 있습니다.
실제 프로젝트의 로컬 실행 화면
기존 프로젝트의 화면 또는 함수를 로컬에서 실행해 촬영했습니다. 개인정보 없는 샘플 입력을 사용했으며, 실행한 범위는 각 이미지 아래에 설명했습니다.
신원·권한·무결성 구분
API Key는 제공자 규칙에 따른 식별자 또는 자격증명입니다. 가능한 작업은 헤더에 값이 있다는 사실이 아니라 권한 범위와 엔드포인트 규약으로 정해집니다. 공개 시세는 키가 필요 없을 수 있고 개인 잔고는 서명 인증을 요구할 수 있습니다. HTTPS는 전송 기밀성·무결성을 제공하며 애플리케이션 서명은 제공자가 정한 서명 재료를 결합합니다. 서명이 HTTPS를 대체하지는 않습니다.
HMAC: 정확한 서명 재료 보존
Binance Spot의 HMAC 키는 문서가 지정한 파라미터 문자열을 HMAC-SHA256으로 처리하고 서명과 API-key 헤더를 전송합니다. 아래 예제는 호출부 입력을 바꾸지 않고 새 필드 목록을 만듭니다. 가상 값의 쿼리 전용 서명 예제이며 운영 어댑터에는 현재 인코딩·파라미터 규칙도 적용해야 합니다.
import hashlib, hmac
from urllib.parse import urlencode, unquote
def hmac_query(pairs, secret, timestamp_ms):
fields = list(pairs) # do not mutate caller input
if any(k in {"signature", "timestamp"} for k, _ in fields):
raise ValueError("signature and timestamp are managed here")
if type(timestamp_ms) is not int:
raise ValueError("explicit integer milliseconds required")
fields.append(("timestamp", str(timestamp_ms)))
query = urlencode(fields)
signature = hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
return query + "&signature=" + signature
# Upbit's documented, unencoded query-hash material for array parameters.
query = unquote(urlencode([("uuids[]", "demo-a"), ("uuids[]", "demo-b")], doseq=True))
assert query == "uuids[]=demo-a&uuids[]=demo-b"
query_hash = hashlib.sha512(query.encode()).hexdigest()
# No network request and no real credential in this example.모든 API가 5초 규칙인 것은 아니다
Binance는 수신 허용 구간과 별도의 미래 시각 검사로 timestamp를 검증합니다. 시각 구간은 재전송 가능한 나이를 제한하지만 주문을 정확히 한 번 실행하게 하지는 않습니다. 호스트 시계를 동기화하고 오차를 측정하며 엔드포인트 단위·한도를 따릅니다. Binance는 RSA·Ed25519 키도 지원하므로 HMAC만 가능한 것은 아닙니다.
JWT: 서명된 인코딩 컨테이너
서명된 compact JWT는 인코딩한 보호 헤더와 페이로드를 점으로 연결한 값을 서명합니다. 원시 JSON 페이로드만 서명하는 것이 아닙니다. 클레임은 대체로 읽을 수 있으며 서명은 암호화가 아닙니다. 관리되는 라이브러리에 문서의 알고리즘을 명시하세요.
업비트는 HS512를 권장하며 새 nonce를 요구합니다. 파라미터가 있으면 SHA512 query hash로 연결합니다. 공식 Python 구성은 urlencode(..., doseq=True)를 unquote하고 필요한 순서와 배열 표현을 보존합니다. 이 정규 재료가 실제 URL의 percent-encoded 바이트와 반드시 같은 것은 아닙니다. 토큰 경계 전체는 연결한 업비트 예제를 참고하세요.
현재 빗썸 문서는 HS256 JWT와 nonce·밀리초 timestamp를 설명합니다. 구분자를 쓰는 과거 HMAC 레시피를 현재 빗썸 전체의 규칙처럼 제시하면 안 됩니다.
토큰과 디버깅도 규약에 맞추기
KIS는 먼저 access token을 발급하고 이후 엔드포인트별 헤더와 만료 처리가 필요합니다. 달력 날짜 대신 명시된 만료 정보로 캐시하고 실전·모의 환경을 분리하세요. REST 토큰과 실시간 approval key의 역할도 다릅니다.
실패 시 안전한 오류 코드·API 버전·키 별칭·시계 오차·정규화 시험 결과를 기록합니다. 가상 서명 데이터를 오프라인에서 비교하고 실제 비밀·토큰 앞부분·서명된 계좌/주문 파라미터는 출력하지 않습니다. 권한은 최소화하고 소스 이력 밖에 키를 보관하며 노출되면 사본 청소 전에 자격증명부터 폐기합니다.
공식 자료와 함께 읽기
Binance authentication · Upbit authentication · Bithumb JWT · JWS signing input · KIS official samples · 업비트 API와 파이썬 연동
내용·예제 검토: 2026-09-29
댓글
댓글 쓰기