WhatsApp Service — Keamanan & Hardening
Dokumen ini merangkum seluruh kontrol keamanan yang telah diimplementasikan pada whatsapp_service (port 8091), mencakup hasil audit keamanan 2026-05-25–2026-06-05.
Keamanan & Hardening
Semua item di bawah telah diimplementasikan dan diverifikasi per audit keamanan 2026-05-29–2026-06-05.
Webhook Security
-
Signature Meta wajib diverifikasi secara eksplisit:
validateMetaSignaturemenolak setiap request apabilaWHATSAPP_APP_SECRETkosong — tidak ada fallback diam-diam ke mode bypass. Pengembang yang membutuhkan bypass untuk lingkungan lokal wajib menyetelWEBHOOK_SIGNATURE_BYPASS=truesecara eksplisit di file env development. Dengan demikian, misconfigurationAPP_ENVdi host production-like tidak bisa secara tidak sengaja menonaktifkan verifikasi HMAC SHA-256. -
Hub.Challenge tolak token kosong:
verifyWebhookChallengemenolak permintaan handshake dari Meta apabilaWHATSAPP_VERIFY_TOKEN(expected token) belum dikonfigurasi. Tidak ada path di mana token kosong diterima sebagai valid — verifikasi tidak bisa di-bypass hanya dengan membiarkan konfigurasi token kosong.
Konfigurasi & Environment
-
Env systemd tidak bisa ditimpa oleh file
.env:whatsapp_servicemenggunakangodotenv.Load(bukangodotenv.Overload). Ini memastikan variabel environment yang sudah di-set oleh directiveEnvironment=di unit systemd tidak dapat ditimpa oleh isi file.env.production. Apabila seorang attacker berhasil memodifikasi file.envdi disk tetapi tidak memiliki akses ke systemd unit file, nilai-nilai kritikal (API key, webhook secret, APP_ENV) yang dikelola oleh systemd tetap berlaku dan tidak dapat dioverride. -
Fail-fast pada konfigurasi kritis kosong:
validateConfig()menolak startup jikaINTERNAL_NOTIFICATION_API_KEY,WHATSAPP_API_SECRET, atauWHATSAPP_VERIFY_TOKENkosong saatAPP_ENV=production. Misconfiguration terdeteksi di waktu startup, bukan saat runtime.
Auth & Authorization
-
Internal API key fail-closed: Middleware
withInternalKeymenggunakansubtle.ConstantTimeCompareuntuk membandingkan API key. JikaINTERNAL_NOTIFICATION_API_KEYkosong, semua request ke endpoint internal ditolak — tidak ada fail-open. Constant-time compare mencegah timing side-channel attack pada shared-secret auth. -
Template whitelist via env: Pengiriman template WhatsApp dibatasi oleh
WHATSAPP_ALLOWED_TEMPLATES— service tidak bisa dipakai untuk mengirim template Meta arbitrary di luar daftar yang diizinkan oleh operator.
Keamanan Jaringan & Transport
-
Binding loopback only: Service hanya listen di
127.0.0.1:8091, tidak ter-expose langsung ke internet. Traffic publik masuk melalui nginx yang kemudian proxy ke service. -
HTTP server timeout lengkap:
http.Serverdikonfigurasi denganReadHeaderTimeout: 5s(mitigasi Slowloris),ReadTimeout: 30s,WriteTimeout: 30s,IdleTimeout: 120s. Tidak ada konfigurasi server tanpa timeout yang berisiko terhadap slow-client atau connection exhaustion.
Observability & PII Protection
-
Phone number di-mask di semua log: Fungsi
maskPhonemenyamarkan nomor telepon sebelum ditulis ke log stream (contoh:+628***68). Data PII merchant tidak pernah muncul dalam bentuk penuh di log eventwhatsapp_sendmaupunwhatsapp_webhook. -
Event log terstruktur dengan taxonomy error:
classifyWAErrormengklasifikasikan 10 kelas error secara konsisten (ok,meta_auth,meta_rate_limit,meta_template_invalid,meta_4xx,meta_5xx,network,network_timeout,unknown). Taxonomy ini memungkinkan monitoring dan alerting yang tepat tanpa perlu expose detail internal ke caller.
Operational Hardening
-
Graceful shutdown 15 detik: Service menangani SIGTERM/SIGINT dengan memberikan window 15 detik bagi in-flight HTTP request untuk selesai sebelum proses berhenti. Hal ini krusial untuk mencegah half-write pada tabel
whatsapp_send_attempts— tanpa graceful shutdown, deploy bisa mengakibatkan baris audit log tersimpan dengan status tidak konsisten karena proses dipaksa berhenti di tengah call ke Meta Cloud API. -
Dockerfile distroless nonroot: Image produksi menggunakan
gcr.io/distroless/static-debian12:nonrootsebagai base image stage 2. Binary berjalan sebagai user nonroot tanpa shell, mengurangi attack surface secara signifikan jika terjadi container escape.
Test Coverage Keamanan
- 343 baris unit test keamanan live: Coverage mencakup
security_test.go(validateConfig production guards + middleware fail-closed + verifyWebhookChallenge),telemetry_test.go(maskPhone + classifyWAError), danwebhook_security_test.go(8 kasus HMAC SHA-256 verify termasuk signature valid, invalid, kosong, dan bypass flag). Seluruh test pass di setiap build.
Dokumen ini merupakan bagian dari seri security documentation Kesles Merchant. Untuk detail arsitektur service lihat architecture.md. Untuk prosedur deploy dan rotasi env lihat deploy-runbook.md.
Penguatan Tambahan (2026-06-08)
-
Idempotency mutual exclusion sebelum eksekusi:
Store.TryLock()menggunakan RedisSetNX(TTL 30s) untuk acquire distributed lock sebelum mengirim pesan — bukan setelah. Request kedua dengan idempotency key yang sama saat lock aktif mendapat 409 Conflict. Duplicate send tidak dapat terjadi meski dua goroutine concurrent membaca cache miss bersamaan. -
UUID format divalidasi sebelum DB query: Handler
GET /messages/{uuid}memvalidasi format UUID path parameter denganisValidUUIDFormat()sebelum query ke database. Input non-UUID tidak pernah mencapai layer SQL — input malformed ditolak 404 di handler level. -
dist/.env dikecualikan dari git tracking:
/dist/.envdan/dist/.env.*ditambahkan secara eksplisit ke.gitignoresebagai belt-and-suspenders — credential di folder build artifact tidak dapat ter-commit secara tidak sengaja.