Chuyển tới nội dung chính

Bảo mật

Tổng quan​

Mọi request giữa Baokim và CashPlus được ký số bằng RSA với hàm băm SHA1:

ChiềuBên kýKhóa dùng để kýBên verifyKhóa dùng để verify
CashPlus → Baokim (gọi API)CashPlusKhóa riêng của CashPlusBaokimKhóa công khai CashPlus đã đăng ký với Baokim
Baokim → CashPlus (webhook)BaokimKhóa riêng của BaokimCashPlusKhóa công khai Baokim cung cấp
  • Chữ ký nằm ở header Signature, mã hóa Base64. Không đưa chữ ký vào body.
  • Dữ liệu được ký là raw body của request, đúng từng byte gửi đi. Không format lại, không thêm/bớt khoảng trắng, không đổi thứ tự trường sau khi ký.
  • Chỉ hỗ trợ SHA1. Chữ ký tạo bằng thuật toán khác sẽ bị từ chối với mã 120.
  • Khóa của môi trường test và production khác nhau. Liên hệ Baokim để trao đổi khóa công khai cho từng môi trường.

CashPlus gọi API Baokim​

Áp dụng cho tất cả API trong tài liệu này:

POST /collection/{env}/users
POST /collection/{env}/v1
POST /transaction/v2/share-amount
POST /transaction/v2/spend
POST /transaction/v2/spend-result
POST /ats/transaction
POST /ats/transaction-payment-share
POST /ats/merchant
POST /ats/user

Bước 1. Tạo body JSON — đây chính là chuỗi sẽ gửi đi:

{"RequestId":"ABC123","RequestTime":"2025-01-15 10:30:00","PartnerCode":"CASHPLUS","Data":[]}

Bước 2. Ký chuỗi body bằng khóa riêng của CashPlus, thuật toán RSA-SHA1, rồi mã hóa Base64:

$body = json_encode($data);
openssl_sign($body, $signature, $privateKey, OPENSSL_ALGO_SHA1);
$signatureBase64 = base64_encode($signature);

Bước 3. Gửi đúng chuỗi $body đã ký, kèm header Signature:

curl -X POST '{BASE_URL}/collection/live/v1' \
-H 'Content-Type: application/json' \
-H 'Signature: <signatureBase64>' \
-d '{"RequestId":"ABC123","RequestTime":"2025-01-15 10:30:00","PartnerCode":"CASHPLUS","Data":[]}'

Sai chữ ký hoặc thiếu header Signature → Baokim trả mã 120.

CashPlus nhận webhook từ Baokim​

Áp dụng cho Webhook thu hộ và Webhook kết quả chi.

Baokim gửi:

  • Header Content-Type: application/json
  • Header Signature: <Base64 của chữ ký RSA-SHA1 trên raw body>

CashPlus verify trên raw body nhận được (không parse rồi encode lại):

$rawBody   = file_get_contents('php://input');
$signature = base64_decode($_SERVER['HTTP_SIGNATURE'] ?? '');

$isValid = openssl_verify($rawBody, $signature, $baokimPublicKey, OPENSSL_ALGO_SHA1);
if ($isValid !== 1) {
// Chữ ký không hợp lệ: không xử lý, trả ResponseCode khác 200
}
$data = json_decode($rawBody, true);

Format response CashPlus cần trả và chính sách gửi lại: xem trang của từng webhook.

Ví dụ Node.js​

const crypto = require('crypto');

// CashPlus ký request gửi Baokim
function signBody(body, privateKeyPem) {
const signer = crypto.createSign('RSA-SHA1');
signer.update(body, 'utf8');
return signer.sign(privateKeyPem, 'base64');
}

// CashPlus verify webhook từ Baokim
function verifyWebhook(rawBody, signatureBase64, baokimPublicKeyPem) {
const verifier = crypto.createVerify('RSA-SHA1');
verifier.update(rawBody, 'utf8');
return verifier.verify(baokimPublicKeyPem, signatureBase64, 'base64');
}

const body = JSON.stringify({
RequestId: 'ABC123',
RequestTime: '2025-01-15 10:30:00',
PartnerCode: 'CASHPLUS',
Data: []
});

fetch('{BASE_URL}/collection/live/v1', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Signature': signBody(body, privateKeyPem) },
body // gửi đúng chuỗi đã ký
});