HMAC-SHA256 인증 규격
암호학적 HMAC-SHA256 요청 서명을 사용하여 SmallPict API에 안전하게 인증하는 방법.
SmallPict API는 전송 계층의 보안을 위해 암호학적 HMAC-SHA256 요청 서명 메커니즘을 전면 적용하고 있습니다.
이 표준은 다음과 같은 보안성을 보장합니다:
- 페이로드 무결성 (Payload Integrity): 전송 도중 HTTP 메서드, 경로, Body 데이터가 위변조되지 않음을 보장.
- 재전송 공격 방어 (Anti-Replay Attack): 엄격한 타임스탬프 유효 윈도우를 통해 탈취된 요청의 재사용 차단.
- 비밀 키 유출 제로 (Zero Secret Exposure): Secret Key가 네트워크 통신망을 통해 전송되지 않음.
필수 HTTP 요청 헤더
인증이 필요한 모든 API 호출에는 다음 3개의 HTTP 헤더가 반드시 포함되어야 합니다:
HTTP
X-API-Key: sp_sdk_9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0bX-Timestamp: 1716301234X-Signature: 3a9f8b2c4d6e8a0f1b3c5d7e9f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a| 헤더 필드 | 데이터 타입 | 상세 설명 |
|---|---|---|
X-API-Key | String | 고객 공개 API 키 (예: sp_sdk_..., sp_wp_..., sp_test_...) |
X-Timestamp | Integer String | 요청 발송 시점의 초 단위 Unix 타임스탬프 |
X-Signature | Hex String | Secret Key로 계산된 64자리 16진수 HMAC-SHA256 서명값 |
서명 생성 알고리즘
1단계: 표준 서명 대상 문자열 (String-To-Sign) 조합
줄바꿈 문자(\n)를 구분자로 하여 HTTP 메서드, 요청 경로, 타임스탬프 및 요청 바디의 SHA-256 해시를 순서대로 연결합니다:
TEXT
{HTTP_METHOD}\n{PATH}\n{TIMESTAMP}\n{BODY_SHA256_HEX}{HTTP_METHOD}: 대문자 HTTP 동사 (예:POST,GET,DELETE).{PATH}: 쿼리 파라미터를 제외한 정확한 요청 URI 경로 (예:/v1/optimize,/v1/quota).{TIMESTAMP}: 요청 헤더의X-Timestamp와 동일한 타임스탬프.{BODY_SHA256_HEX}: 원본 요청 바디의 SHA-256 16진수 해시값.GET요청이나 빈 바디의 경우 빈 문자열의 SHA-256 해시 사용:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
2단계: HMAC-SHA256 해시 연산
TEXT
Signature = hex(HMAC_SHA256(SecretKey, StringToSign))공식 언어별 서명 구현 코드
Node.js (TypeScript)
TypeScript
import crypto from 'node:crypto';
export function signRequest( method: string, path: string, secretKey: string, bodyString: string = '') { const timestamp = Math.floor(Date.now() / 1000).toString(); const bodyHash = crypto.createHash('sha256').update(bodyString).digest('hex'); const stringToSign = `${method.toUpperCase()}\n${path}\n${timestamp}\n${bodyHash}`; const signature = crypto .createHmac('sha256', secretKey) .update(stringToSign) .digest('hex');
return { timestamp, signature };}Python 3
Python
import hmacimport hashlibimport time
def sign_request(method: str, path: str, secret_key: str, body_bytes: bytes = b"") -> tuple[str, str]: timestamp = str(int(time.time())) body_hash = hashlib.sha256(body_bytes).hexdigest() string_to_sign = f"{method.upper()}\n{path}\n{timestamp}\n{body_hash}" signature = hmac.new( secret_key.encode("utf-8"), string_to_sign.encode("utf-8"), hashlib.sha256 ).hexdigest() return timestamp, signatureGo
Go
package main
import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "strconv" "time")
func SignRequest(method, path, secretKey string, body []byte) (timestamp string, signature string) { ts := strconv.FormatInt(time.Now().Unix(), 10) h := sha256.Sum256(body) bodyHash := hex.EncodeToString(h[:]) stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", method, path, ts, bodyHash)
mac := hmac.New(sha256.New, []byte(secretKey)) mac.Write([]byte(stringToSign)) return ts, hex.EncodeToString(mac.Sum(nil))}타임스탬프 허용 오차 범위 (±300초)
재전송 공격을 방지하기 위해 SmallPict 게이트웨이는 서버 시간과 클라이언트 시간의 오차를 ±300초(5분) 이내로 엄격히 제한합니다.
|server_time - X-Timestamp| > 300인 요청은 즉시 401 Unauthorized (ERR_TIMESTAMP_DRIFT)로 거부됩니다. 서버의 NTP 시간 동기화를 확인하세요.