Skip to main content

Integration API — Keamanan & Hardening

Auth & Authorization

  • 3-tier JWT validation: requireAuth membedakan issuer JWT — staff (kesles-merchant-auth) vs merchant (kesles-integration) — payload claim divalidasi sebelum inject ke context.
  • Role cache 30 detik: Role staff di-cache per userID selama 30 detik untuk mengurangi call ke auth_service per request tanpa mengorbankan freshness.
  • Merchant JWT hanya berlaku untuk scope sendiri: Handler sandbox yang menerima merchant JWT membaca ac.MerchantID dari token — merchant tidak dapat meng-query transaksi milik merchant lain.
  • SuperAdmin dapat meng-override scope via ?merchant_id=: Hanya staff dengan role superAdmin yang dapat menambahkan query param merchant_id untuk mengakses data merchant lain.

PSP Secret Handling

  • HMAC secret di-encrypt AES-256-GCM: decryptSecretAES decode format hex nonce || ciphertext || GCM-tag — secret tidak pernah disimpan plaintext di DB payment_service.
  • Key lookup via payment_service: Secret selalu di-fetch dari payment_service /internal/psp/api-keys (bukan DB langsung) — integration_api tidak punya koneksi ke db_payment.

Webhook Sandbox

  • URL allowlist untuk PSP tester: Path PSP yang boleh di-forward dibatasi oleh allowlist eksplisit (/api/psp/v1/merchants, /api/psp/v1/payment-events/, /internal/transactions/, /internal/notifications/) — arbitrary path injection tidak dimungkinkan.
  • URL scheme validation untuk webhook trigger: webhook_url harus dimulai dengan http:// atau https:// — karakter non-URL atau protokol arbitrer ditolak sebelum request keluar.
  • Timeout 15 detik pada webhook delivery: sandboxWebhookClient dikonfigurasi 15s timeout — integration_api tidak dapat di-block oleh endpoint merchant yang lambat/tidak responsif.
  • Response body dibatasi 8 KB: io.LimitReader(resp.Body, 8*1024) pada webhook delivery — response sangat besar dari endpoint merchant tidak di-buffer seluruhnya ke memory.
  • HMAC sandbox signature opsional: X-Sandbox-Signature: sha256=<hmac> hanya dikirim jika operator mengisi secret — tidak ada secret default/hardcoded.

Sandbox Access Control

  • Whitelist eksplisit per merchant: Merchant hanya bisa akses sandbox setelah super admin menambahkan ke integration.merchant_sandbox_access — tidak ada akses default.
  • Scoping transaksi pada query: getSandboxTransaction menyertakan merchant_id = $2 pada WHERE untuk merchant JWT — injection transaction_id milik merchant lain di-reject di query layer.
  • Idempotent enable: enableMerchantSandbox menggunakan ON CONFLICT (merchant_id) DO NOTHING — double-enable tidak membuat duplikat record.

Hardening Baseline (8-item)

ItemStatus
validateConfig fail-fast (fatal jika JWT_SECRET/token kosong di production)
Constant-time API key comparison
HTTP client timeout (10s default, 15s webhook, 20s PSP)
Graceful shutdown (SIGTERM → http.Server.Shutdown)
slog event taxonomy (snake_case, tidak ada PII di log)
PostgreSQL pool: 25 max, 5 idle, 5min lifetime
pgx/v5 via stdlib adapter
APP_ENV=production eksplisit di .env line 1