
Hari 11: AI Audit Temukan 5 Bug yang Scanner Lewati
Hari kesebelas! AI audit menemukan 5 celah keamanan yang Trivy dan Semgrep gak tangkap — input validation, auth, security headers, body size limit, dan transaction logging.
Scanner Hijau, Tapi Aman?
Trivy: 0 CVE. Semgrep: cuma 1 WARNING (HTTP tanpa TLS, yang udah kita accept). Pipeline hijau, 4/4 job pass.
Tapi apakah berarti aplikasi kita aman?
Nggak. Ini pelajaran penting dari Hari 11: scanner otomatis itu penting, tapi gak cukup. Scanner cuma deteksi pattern yang udah diketahui —CVE di dependensi, insecure crypto, hardcoded secret. Tapi ada kategori kerentanan yang gak bisa di-capturnya pattern matching.
Apa yang AI Audit Temukan
Dari output Trivy dan Semgrep, kita kasih ke AI buat menganalisis. AI nemuin 5 kerentanan yang scanner otomatis lewati:
| # | Temuan | Severity | Kenapa Scanner Lewati |
|---|---|---|---|
| 1 | Tidak ada input validation di /transfer (negative amount, zero, empty ID) |
HIGH | Gak ada CVE atau pattern yang bisa di-match Semgrep |
| 2 | Tidak ada autentikasi di /balance dan /transfer — siapa aja bisa akses |
HIGH | Ini business logic, bukan pattern yang SAST scan |
| 3 | Tidak ada security headers (X-Content-Type-Options, X-Frame-Options, dll) | MEDIUM | Scanner fokus ke kode, bukan HTTP response |
| 4 | Tidak ada request body size limit — vulnerable ke DoS | MEDIUM | Gak ada CVE buat "missing rate limiter" |
| 5 | Tidak ada audit logging buat transaksi keuangan | MEDIUM | Business logic gap, bukan vulnerability pattern |
Lima kerentanan, dan Trivy + Semgrep tangkap 0 dari 5. Ini bukti bahwa pipedependensi scanning saja gak cukup.
Perbaikan yang Diterapkan
1. Input Validation di /transfer
Sebelumnya, endpoint /transfer nerima apa aja — amount negatif, amount nol, account ID kosong. Sekarang:
if req.Amount <= 0 {
// reject negative and zero amounts
}
if req.Amount > maxTransferAmount {
// reject unreasonably large amounts (cap 1 billion)
}
if math.IsInf(req.Amount, 0) || math.IsNaN(req.Amount) {
// reject infinity and NaN
}
if req.From == "" || req.To == "" {
// reject empty account IDs
}
2. JWT Authentication Middleware
Sekarang /balance dan /transfer butuh Authorization: Bearer <token> header. Invalid token? 401 Unauthorized.
func RequireAuth(jwtSecret []byte, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token, err := jwt.Parse(tokenStr, verifyFunc)
if err != nil || !token.Valid {
http.Error(w, "invalid token", http.StatusUnauthorized)
return
}
next(w, r)
}
}
Token di-generate pake golang-jwt/jwt/v5 (library yang udah kita remediasi di Day 7) dengan GenerateToken() dan ParseToken().
3. Security Headers Middleware
Setiap response sekarang punya headers keamanan:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Cache-Control: no-store
Content-Security-Policy: default-src 'none'
X-XSS-Protection: 0
4. Request Body Size Limit
func LimitBodySize(maxBytes int64, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.ContentLength > maxBytes {
http.Error(w, "request body too large", http.StatusRequestEntityTooLarge)
return
}
r.Body = http.MaxBytesReader(w, r.Body, maxBytes)
next(w, r)
}
}
/healthdan/balance: 1 KB/transfer: 4 KB
5. Transaction Logging
Setiap transfer sekarang di-log:
log.Printf("TRANSFER from=%s to=%s amount=%.2f", req.From, req.To, req.Amount)
Audit trail ini penting buat forensic kalau ada masalah.
Middleware Chain
Semua middleware di-chain secara bersih:
// Protected endpoints
authBalance := SecurityHeaders(LimitBodySize(1024, RequireAuth(jwtSecret, getBalance)))
authTransfer := SecurityHeaders(LimitBodySize(4096, RequireAuth(jwtSecret, transfer)))
// Public endpoint (still has security headers)
publicHealth := SecurityHeaders(LimitBodySize(1024, healthCheck))
Hasil
24 unit tests — PASS
go build — OK
Semgrep — 1 WARNING (HTTP/TLS, accepted, same as before)
Trivy — 0 CVE
Perbandingan Sebelum dan Sesudah
| Aspek | Sebelum (Day 10) | Sesudah (Day 11) |
|---|---|---|
| Input validation | Tidak ada | Negative/zero/empty/NaN amount ditolak |
| Autentikasi | Tidak ada | JWT Bearer token wajib |
| Security headers | Tidak ada | 5 headers keamanan aktif |
| Body size limit | Tidak ada | 1 KB (read), 4 KB (transfer) |
| Transaction logging | Tidak ada | Log setiap transfer |
| Unit tests | 8 | 24 (3x lebih banyak) |
| Dependencies | gin (unused) | gin dihapus, jwt/v5 active |
Lesson Learned
1. Scanner otomatis itu necessary tapi gak sufficient. Trivy nemuin CVE di dependensi. Semgrep nemuin insecure pattern di kode. Tapi keduanya gak bisa deteksi "missing auth" atau "missing input validation" karena itu masalah business logic, bukan pattern.
2. AI audit mengisi gap antara scanner dan manual review. AI bisa analisis arsitektur, flow, dan missing controls yang scanner lewati. Tapi AI tetap butuh human judgment buat prioritas dan accept/reject saran.
3. Middleware chain di Go itu elegan. Dengan http.HandlerFunc chaining, kita bisa compose security layers tanpa duplicate code: headers → body limit → auth → handler.
4. http.MaxBytesReader gak cukup sendirian. Perlu check Content-Length header upfront juga, karena MaxBytesReader cuma enforce saat body di-read. Kalau handler gak read body (misalnya error middleware), limit gak kepenuhi.
5. go mod tidy itu penting. Setelah replace blank import gin dengan real import jwt, go mod tidy otomatis hapus gin dari go.mod — dependency yang gak terpakai gak boleh nge-bloat binary.
Lanjut ke Hari 12
Sekarang SecureBank API punya 5 lapis pertahanan di level kode: input validation, JWT auth, security headers, body size limit, dan transaction logging. Plus 4 lapis di pipeline: build/test, secret scan, SCA, dan SAST.
Besok: Hari 12 — Pipeline Optimization — bikin pipeline total jalan di bawah 2 menit pake Go module cache dan parallel jobs.
Diskusi & Komentar
Artikel Terkait
Hari 5: Trivy SCA Scan Nemukan 4 CVE di Golang API
Hari kelima 60 hari DevSecOps! Scan dependensi Go pakai Trivy dan nemukan 4 CVE termasuk 1 CRITICAL — termasuk library deprecated jwt-go.
Hari 8: Semgrep SAST Scan Temukan Kode Tidak Aman
Hari kedelapan 60 hari DevSecOps! Install Semgrep, buat kode insecure (MD5), dan scan ketemu 2 finding — MD5 weak hash dan HTTP server tanpa TLS.
Hari 10: MD5 ke Bcrypt, Pipeline Hijau Lagi
Hari kesepuluh 60 hari DevSecOps! Fix SAST findings — ganti MD5 ke bcrypt, hapus custom rule HTTP TLS, dan pipeline CI kembali hijau setelah 4 job semua pass.