Skip to content
smallPict

Tiêu chuẩn xác thực HMAC-SHA256

Cách xác thực các yêu cầu gửi đến SmallPict API bằng chữ ký mật mã học HMAC-SHA256.

SmallPict bảo vệ toàn bộ lưu lượng API bằng cơ chế ký yêu cầu mật mã học HMAC-SHA256.

Tiêu chuẩn này mang lại 3 lớp bảo vệ cốt lõi:

  1. Tính toàn vẹn dữ liệu (Payload Integrity): Nội dung phần thân yêu cầu và đường dẫn URI không thể bị thay đổi trên đường truyền.
  2. Chống tấn công phát lại (Anti-Replay Attack): Giới hạn chênh lệch thời gian ngăn chặn việc sử dụng lại các yêu cầu bị nghe lén.
  3. Không để lộ khóa bí mật (Zero Secret Exposure): Khóa Secret Key của bạn không bao giờ được gửi qua đường truyền Internet.

Các tiêu đề HTTP bắt buộc

Mỗi yêu cầu API có xác thực đều phải bao gồm 3 tiêu đề HTTP sau:

HTTP
X-API-Key: sp_sdk_9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0bX-Timestamp: 1716301234X-Signature: 3a9f8b2c4d6e8a0f1b3c5d7e9f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a
Tiêu đềKiểuMô tả chi tiết
X-API-KeyChuỗiKhóa API công khai của bạn (ví dụ: sp_sdk_..., sp_wp_..., sp_test_...)
X-TimestampChuỗi số nguyênDấu thời gian Unix Epoch tính bằng giây tại thời điểm gửi
X-SignatureChuỗi HexChữ ký HMAC-SHA256 mã hóa thập lục phân tạo bởi khóa Secret Key

Thuật toán tạo chữ ký

Bước 1: Ghép chuỗi chuẩn hóa cần ký (Canonical String-To-Sign)

Nối phương thức HTTP, đường dẫn, dấu thời gian và mã băm SHA-256 của phần thân yêu cầu bằng ký tự xuống dòng (\n):

TEXT
{HTTP_METHOD}\n{PATH}\n{TIMESTAMP}\n{BODY_SHA256_HEX}
  • {HTTP_METHOD}: Động từ HTTP viết hoa (ví dụ: POST, GET, DELETE).
  • {PATH}: Đường dẫn URI chính xác không bao gồm tham số truy vấn (ví dụ: /v1/optimize, /v1/quota).
  • {TIMESTAMP}: Dấu thời gian Unix tính bằng giây khớp với tiêu đề X-Timestamp.
  • {BODY_SHA256_HEX}: Mã băm SHA-256 dạng hex của phần thân dữ liệu gốc. Đối với yêu cầu GET hoặc không có nội dung body, sử dụng mã băm của chuỗi rỗng: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.

Bước 2: Tính toán chữ ký HMAC-SHA256

TEXT
Signature = hex(HMAC_SHA256(SecretKey, StringToSign))

Mã nguồn mẫu tạo chữ ký

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, signature

Go

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))}

Giới hạn độ lệch thời gian cho phép (±300 giây)

Để ngăn chặn các cuộc tấn công phát lại, hệ thống cổng API của SmallPict áp dụng giới hạn dung sai thời gian ±300 giây (5 phút).

Các yêu cầu có |server_time - X-Timestamp| > 300 giây sẽ bị từ chối với mã lỗi 401 Unauthorized (ERR_TIMESTAMP_DRIFT). Hãy đảm bảo máy chủ của bạn được đồng bộ thời gian chuẩn qua giao thức NTP.