跳至主要内容

身份驗證概述

VertexPlay API 使用多層身份驗證機制來確保 API 請求的安全性。

驗證流程

請求標頭

所有 API 請求都必須包含以下標頭:

驗證請求 (/v2/auth)

標頭類型必填說明
Content-Typestring必須為 application/json
x-agentidstring營運商代理 ID
x-timestampstringUnix 時間戳(毫秒)
x-noncestring32 字元隨機字符串(用於防重放攻擊)
x-signaturestringSHA256 簽章

其他 API 請求

標頭類型必填說明
AuthorizationstringBearer token,格式:Bearer {accessToken}
Content-Typestring必須為 application/json
x-agentidstring營運商代理 ID
x-timestampstringUnix 時間戳(毫秒)
x-noncestring32 字元隨機字符串
x-signaturestringSHA256 簽章

簽章生成

簽章使用 SHA256 算法生成,確保請求的完整性和真實性。

簽章步驟

  1. 準備簽章字符串:將以下參數按順序連接

    agentId + timestamp + nonce + requestBody
  2. 生成簽章:使用 SHA256 算法

    signature = SHA256(signatureString)
  3. 添加到請求標頭:將生成的簽章放入 x-signature 標頭

Node.js 範例

const crypto = require('crypto');

function generateSignature(agentId, timestamp, nonce, requestBody) {
// 將請求體轉為字符串
const bodyString = JSON.stringify(requestBody);

// 組合簽章字符串
const signatureString = agentId + timestamp + nonce + bodyString;

// 生成 SHA256 簽章
const signature = crypto
.createHash('sha256')
.update(signatureString)
.digest('hex');

return signature;
}

// 使用範例
const agentId = 'integratorNBTest04';
const timestamp = Date.now().toString();
const nonce = crypto.randomBytes(16).toString('hex');
const requestBody = {
cipherText: 'G0ZMDELeJwx+7JcIfIFO...'
};

const signature = generateSignature(agentId, timestamp, nonce, requestBody);

Python 範例

import hashlib
import json
import time
import secrets

def generate_signature(agent_id, timestamp, nonce, request_body):
# 將請求體轉為字符串
body_string = json.dumps(request_body, separators=(',', ':'))

# 組合簽章字符串
signature_string = agent_id + timestamp + nonce + body_string

# 生成 SHA256 簽章
signature = hashlib.sha256(
signature_string.encode('utf-8')
).hexdigest()

return signature

# 使用範例
agent_id = 'integratorNBTest04'
timestamp = str(int(time.time() * 1000))
nonce = secrets.token_hex(16)
request_body = {
'cipherText': 'G0ZMDELeJwx+7JcIfIFO...'
}

signature = generate_signature(agent_id, timestamp, nonce, request_body)

數據加密

所有請求的敏感數據都使用 AES-256-GCM 加密,響應為明文 JSON 格式。

加密格式

{
"cipherText": "ivBase64(16字元) + authTagBase64(24字元) + encryptedDataBase64"
}

加密參數

  • 算法:AES-256-GCM
  • 密鑰長度:256 位(32 字節)
  • IV 長度:96 位(12 字節)
  • 認證標籤長度:128 位(16 字節)

cipherText 結構說明

cipherText 由三個部分組成,全部使用 base64 編碼:

  1. IV (Initialization Vector)

    • 長度:12 bytes
    • Base64 編碼後:16 字元
    • 位置:cipherText[0:16]
  2. Auth Tag (認證標籤)

    • 長度:16 bytes
    • Base64 編碼後:24 字元
    • 位置:cipherText[16:40]
  3. Encrypted Data (加密數據)

    • 長度:變長,取決於原始數據
    • Base64 編碼
    • 位置:cipherText[40:]

解密範例 (Node.js)

const crypto = require('crypto');

const AES_ALGORITHM = 'aes-256-gcm';

/**
* 解密 cipherText
* @param {string} key - AES 密鑰 (hex 格式)
* @param {string} cipherText - 加密文本
* @returns {Object} - 解密後的 JSON 物件
*/
function symmetricDecrypt(key, cipherText) {
try {
const aesKey = Buffer.from(key, 'hex');

// 從密文分離 iv, authTag 和加密資料
const ivLength = 16; // base64 編碼的 12 bytes
const authTagLength = 24; // base64 編碼的 16 bytes

const ivBase64 = cipherText.substring(0, ivLength);
const authTagBase64 = cipherText.substring(ivLength, ivLength + authTagLength);
const encryptedData = cipherText.substring(ivLength + authTagLength);

const aesIv = Buffer.from(ivBase64, 'base64');
const authTag = Buffer.from(authTagBase64, 'base64');

// 建立解密器
const decipher = crypto.createDecipheriv(AES_ALGORITHM, aesKey, aesIv);
decipher.setAuthTag(authTag); // 設置認證標籤,GCM 會自動驗證完整性

// 解密
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
decrypted += decipher.final('utf8'); // 如果 authTag 驗證失敗,這裡會拋出錯誤

return JSON.parse(decrypted);
} catch (e) {
throw new Error(`Symmetric Decryption Failed: ${e.message}`);
}
}

// 使用範例
const key = 'your-32-byte-hex-key'; // 64 個 hex 字元 = 32 bytes
const cipherText = 'G0ZMDELeJwx+7JcI...'; // 完整的 cipherText

try {
const decryptedData = symmetricDecrypt(key, cipherText);
console.log('Decrypted data:', decryptedData);
} catch (error) {
console.error('Decryption error:', error.message);
}

加密範例 (Node.js)

/**
* 加密數據
* @param {string} key - AES 密鑰 (hex 格式)
* @param {Object} data - 要加密的 JSON 物件
* @returns {string} - 加密後的 cipherText
*/
function symmetricEncrypt(key, data) {
try {
const aesKey = Buffer.from(key, 'hex');

// 生成隨機 IV (12 bytes)
const aesIv = crypto.randomBytes(12);

// 建立加密器
const cipher = crypto.createCipheriv(AES_ALGORITHM, aesKey, aesIv);

// 加密數據
const jsonString = JSON.stringify(data);
let encrypted = cipher.update(jsonString, 'utf8', 'base64');
encrypted += cipher.final('base64');

// 獲取認證標籤 (16 bytes)
const authTag = cipher.getAuthTag();

// 組合 cipherText: ivBase64 + authTagBase64 + encryptedData
const cipherText = aesIv.toString('base64') +
authTag.toString('base64') +
encrypted;

return cipherText;
} catch (e) {
throw new Error(`Symmetric Encryption Failed: ${e.message}`);
}
}

// 使用範例
const data = {
username: 'player001',
amount: 100
};

const cipherText = symmetricEncrypt(key, data);
console.log('Encrypted cipherText:', cipherText);

錯誤處理

驗證錯誤碼

狀態碼說明
84解密失敗 - 可能是密鑰錯誤或數據損壞
83認證失敗 - 簽章驗證失敗或參數錯誤

錯誤響應格式

{
"code": 83,
"message": "Signature verification failed",
"logUUID": "6589bf8d-fe74-48bd-841a-71bf8f848f86"
}

安全建議

  1. 保護 Secret Key:絕不在客戶端代碼或公開位置存儲 Secret Key
  2. 使用 HTTPS:所有 API 請求必須通過 HTTPS 傳輸
  3. 時間戳驗證:確保時間戳在合理範圍內(建議 ±1 分鐘)
  4. Nonce 唯一性:每個請求使用唯一的 nonce 防止重放攻擊
  5. Token 管理:定期刷新 accessToken,不要長期使用同一個 token
  6. 錯誤處理:妥善處理認證錯誤,避免洩露敏感信息

下一步

了解如何獲取 Access Token 來開始使用 API。