Skip to content

cURL

適合快速驗證鑑權鏈路或在 CI 裡跑健康檢查。

依賴

  • bash / zsh
  • openssl
  • awk

不要在 cURL 命令上構建生產業務

shell 轉義複雜、錯誤處理弱。生產請用 Python / Node / Go 等。

列卡頭(最簡單的成功路徑)

bash
APP_ID="cp_a1b2c3d4..."
SECRET="f1e2d3c4..."
BASE="https://api.coinepay.net"
PATH_VAL="/api/v1/openapi/card_headers/list"
BODY='{"page":1,"page_size":20}'

TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -hex | awk '{print $2}')
SIGN_INPUT=$(printf 'POST\n%s\n\n%s\n%s\n%s' "$PATH_VAL" "$TS" "$NONCE" "$BODY_HASH")
SIG=$(echo -n "$SIGN_INPUT" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')

curl -X POST "$BASE$PATH_VAL" \
  -H "X-App-Id: $APP_ID" \
  -H "X-Timestamp: $TS" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIG" \
  -H "Content-Type: application/json" \
  -d "$BODY"

申請虛擬卡(帶冪等鍵)

bash
PATH_VAL="/api/v1/openapi/card/apply"
BODY='{"header_id":"hdr_5","package_id":"pkg_12","first_name":"John","last_name":"Doe"}'
IDEMPOTENCY_KEY=$(uuidgen)   # macOS/Linux 通用

TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -hex | awk '{print $2}')
SIGN_INPUT=$(printf 'POST\n%s\n\n%s\n%s\n%s' "$PATH_VAL" "$TS" "$NONCE" "$BODY_HASH")
SIG=$(echo -n "$SIGN_INPUT" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')

curl -X POST "$BASE$PATH_VAL" \
  -H "X-App-Id: $APP_ID" \
  -H "X-Timestamp: $TS" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIG" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d "$BODY"

通用簽名指令碼

把以下儲存為 ~/sign.shchmod +x ~/sign.sh

bash
#!/usr/bin/env bash
# 用法:sign.sh <method> <path> <body_json>
# 輸出:4 行 header(X-App-Id / X-Timestamp / X-Nonce / X-Signature)
# 呼叫前需 export APP_ID 和 SECRET

set -euo pipefail
METHOD="${1:-POST}"
PATH_VAL="$2"
BODY="${3:-{}}"

: "${APP_ID:?APP_ID env var required}"
: "${SECRET:?SECRET env var required}"

TS=$(date +%s)
NONCE=$(openssl rand -hex 16)
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 -hex 2>/dev/null | awk '{print $2}')
SIGN_INPUT=$(printf '%s\n%s\n\n%s\n%s\n%s' "$METHOD" "$PATH_VAL" "$TS" "$NONCE" "$BODY_HASH")
SIG=$(echo -n "$SIGN_INPUT" | openssl dgst -sha256 -hmac "$SECRET" -hex 2>/dev/null | awk '{print $2}')

cat <<EOF
X-App-Id: $APP_ID
X-Timestamp: $TS
X-Nonce: $NONCE
X-Signature: $SIG
EOF

使用:

bash
export APP_ID="cp_..."
export SECRET="f1e2d3c4..."

PATH_VAL="/api/v1/openapi/card_headers/list"
BODY='{"page":1,"page_size":20}'

# 拿到 4 行 header
HEADERS=$(~/sign.sh POST "$PATH_VAL" "$BODY")

# 轉成 curl -H 引數(每行一個 -H)
CURL_HEADERS=$(echo "$HEADERS" | awk '{print "-H \"" $0 "\""}' | tr '\n' ' ')

eval curl -X POST "https://api.coinepay.net$PATH_VAL" \
  $CURL_HEADERS \
  -H \"Content-Type: application/json\" \
  -d "'$BODY'"

驗籤 webhook

bash
# 假設你抓到一個 webhook:
RAW_BODY='{"card_id":"card_12345","status":"opened","opened_at":"2026-04-29T11:00:12Z"}'
SIG_HEADER='v1,9b8e7f6d5c4b3a2918273645d4e3c2b1a0f9e8d7c6b5a4938271605f4e3d2c1b'
TS_HEADER='1714377612'
WEBHOOK_SECRET='your_webhook_secret_64_hex'

SIG="${SIG_HEADER#v1,}"
EXPECTED=$(printf '%s.%s' "$TS_HEADER" "$RAW_BODY" | \
  openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" -hex | awk '{print $2}')

if [ "$SIG" = "$EXPECTED" ]; then
  echo "OK"
else
  echo "FAIL"
fi

shell 驗籤僅供除錯

生產環境的 webhook 驗籤必須用程式語言實現(恆定時間比較 + 嚴格的 raw body 處理)。shell 比較不是恆定時間。

採用 MIT 等價條款釋出