Skip to content

Bảo mật ​

Ký callback của bạn ​

Mỗi OOB callback phải mang một header signature. Cơ chế ký là HMAC-SHA256 trên raw request body, dùng khóa dùng chung (shared secret), sau đó mã hóa Base64:

signature = base64_standard( HMAC_SHA256( raw_request_body, hex_decode(shared_key) ) )

Hai chi tiết quyết định signature của bạn có được xác minh thành công hay không:

  • Khóa là một chuỗi hex. Hãy decode nó thành bytes trước khi dùng làm khóa HMAC. Dùng trực tiếp các ký tự hex làm key material sẽ tạo ra một signature trông có vẻ hợp lệ nhưng không bao giờ khớp.
  • Ký đúng những byte bạn gửi. Serialize body một lần, ký chính mảng byte đó, và gửi đi đúng mảng byte đó. Việc serialize lại giữa lúc ký và lúc gửi — một hệ quả thường gặp khi truyền một object cho một HTTP client rồi client đó tự encode lại — có thể đổi thứ tự key hoặc thay đổi khoảng trắng, khiến signature không còn khớp với body nhận được.

Go ​

go
func signBody(body []byte, hexKey string) (string, error) {
    key, err := hex.DecodeString(hexKey)
    if err != nil {
        return "", err
    }
    mac := hmac.New(sha256.New, key)
    mac.Write(body)
    return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
}

// body phải là cùng một []byte được truyền vào request:
sig, _ := signBody(body, sharedKeyHex)
req.Header.Set("signature", sig)

Node.js ​

javascript
import { createHmac } from "node:crypto";

function signBody(body, hexKey) {
  return createHmac("sha256", Buffer.from(hexKey, "hex"))
    .update(body)
    .digest("base64");
}

// body phải là cùng một string được truyền làm request body:
const body = JSON.stringify(payload);
const signature = signBody(body, sharedKeyHex);

Kiểm tra thủ công ​

bash
BODY='{"TransactionId":"...","StepupRequestId":"...","Status":"SUCCESS"}'
KEY=<your_shared_key_hex>

SIG=$(printf '%s' "$BODY" \
  | openssl dgst -sha256 -mac HMAC -macopt hexkey:$KEY -binary \
  | base64)

curl -sS -X POST "$OOB_CALLBACK_URL" \
  -H 'Content-Type: application/json' \
  -H "signature: $SIG" \
  -d "$BODY"

Lưu ý dùng printf '%s' thay vì echo — echo thêm một ký tự xuống dòng, vốn là một phần của body bạn ký nhưng lại dễ bị mất khi request được gửi đi, khiến signature không khớp.

Request gửi đến từ ACS ​

Các lệnh gọi từ ACS đến nền tảng của bạn không được ký ở tầng ứng dụng. Chúng được bảo vệ ở tầng mạng: hãy giới hạn endpoint của bạn chỉ chấp nhận các dải IP nguồn đã trao đổi trong quá trình onboarding, và phục vụ chúng qua TLS.

Chống replay ​

ACS đối chiếu mỗi callback với StepupRequestId và trạng thái hiện tại của phiên đó. Một callback cho một phiên đã final sẽ bị bỏ qua, nên một request bị replay không thể ghi đè lên một kết quả đã được ghi nhận.

Dữ liệu chủ thẻ ​

Số thẻ đầy đủ (full PAN) chỉ xuất hiện ở đúng một nơi: request /step_up. Không có gì khác trong tích hợp này mang theo nó.

Hãy giữ request đó bên trong môi trường dữ liệu chủ thẻ (cardholder data environment) của bạn, và không để nó lọt vào log. Nếu bạn log request body theo mặc định, hãy thêm một ngoại lệ cho endpoint này trước khi go-live — không phải sau đó.

Xoay vòng khóa (Key rotation) ​

Khóa HMAC dùng chung là một credential production. Hãy thống nhất lịch xoay vòng trong quá trình onboarding và phối hợp với Cake khi thay đổi; cả hai bên phải chuyển đổi cùng lúc, vì chỉ có một khóa đang hoạt động tại một thời điểm.

Developers