Integrasi Backend•Security & RSA

Keamanan & Verifikasi RSA-SHA256 Signature

Setiap callback webhook dilengkapi dengan header HTTP Signature. Header ini berfungsi membuktikan secara kriptografis bahwa payload benar-benar dikirimkan oleh core gateway resmi Qoin dan tidak mengalami modifikasi (tampering) di perjalanan.

Algoritma & Ketentuan Verifikasi

  • Algoritma Kriptografi: SHA256withRSA (RSA-PKCS#1 v1.5 dengan digest hash SHA-256).
  • Format Signature: Base64 encoded string pada HTTP Header Signature.
  • Kunci Verifikasi: Gateway RSA Public Key resmi (format PEM X.509 SPKI).
Aturan Emas: Verifikasi Harus pada Raw HTTP Body
PENTING: Verifikasi signature wajib dilakukan terhadap Raw HTTP Body byte-for-byte persis sebelum payload JSON diparsing ke dalam objek/array. Jika framework mem-parse JSON terlebih dahulu lalu men-serialize ulang (JSON.stringify() atau json_encode()), urutan key dan spasi whitespace akan berubah, sehingga verifikasi signature akan gagal!

Contoh Kode Verifikasi Multi-Bahasa

Coba Live Tester
import express from 'express';
import crypto from 'crypto';

const app = express();
const GATEWAY_PUBLIC_KEY = process.env.GATEWAY_PUBLIC_KEY; // Format PEM

function verifyCallbackSignature(rawBody: string, signatureBase64: string, publicKeyPem: string): boolean {
  try {
    const verifier = crypto.createVerify('RSA-SHA256');
    verifier.update(rawBody, 'utf8');
    return verifier.verify(publicKeyPem, signatureBase64, 'base64');
  } catch (err) {
    return false;
  }
}

// PENTING: Gunakan express.raw() agar raw body tetap berupa Buffer asli
app.post('/webhook/qoin', express.raw({ type: 'application/json' }), (req, res) => {
  const rawBody = req.body.toString('utf8');
  const signature = req.headers['signature'] as string;

  if (!signature || !verifyCallbackSignature(rawBody, signature, GATEWAY_PUBLIC_KEY)) {
    return res.status(401).json({ message: 'Invalid Signature' });
  }

  // Baru setelah valid, parse body ke JSON
  const payload = JSON.parse(rawBody);
  console.log('Valid Callback Received:', payload);

  // Return HTTP 200 secepatnya
  return res.status(200).json({ status: 'OK' });
});