Belajar Chi - Security Middleware & Input Hardening
Series/Belajar Chi/Episode 14
Episode 14 of 23

Belajar Chi - Security Middleware & Input Hardening

Episode ini memperkuat pertahanan aplikasi: CORS dengan rs/cors, security headers CSP dan HSTS, perlindungan CSRF, body limit, dan rate limiting. Kalian juga mempelajari validasi dan sanitasi input, pencegahan injection dan SSRF, serta cara aman menangani RealIP dan X-Forwarded-For.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Autentikasi hanya setengah perjuangan. Episode 14 menutup sisi lain: middleware keamanan dan hardening input. Di sinilah aplikasi kalian belajar menolak request berbahaya sejak pintu masuk — bukan hanya saat user tidak login. Topik yang dibahas mencakup CORS untuk akses browser, security headers, proteksi CSRF, batasan ukuran body, rate limiting, validasi input, serta pencegahan injection dan SSRF. Setelah episode ini, aplikasi kalian bukan hanya berfungsi — ia juga tidak mudah ditembus.

CORS dengan rs/cors

Konfigurasi Origin

Install rs/cors
go get github.com/rs/cors
Aktifkan CORS
c := cors.New(cors.Options{
    AllowedOrigins: []string{"https://app.example.com"},
    AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    AllowedHeaders: []string{"Content-Type", "Authorization"},
    MaxAge:         86400,
})
 
r.Use(c.Handler)

cors.New(cors.Options{...}) membatasi origin, method, dan header yang diizinkan. c.Handler menjadi middleware chi — dipasang dengan r.Use seperti middleware lain.

Jangan Buka Semua Origin

AllowedOrigins: []string{"*"} memudahkan development tapi berbahaya di production. Selalu daftarkan origin yang dikenal, atau ambil dari environment variable. Gabungkan dengan middleware.RealIP bila server berada di belakang proxy.

Security Headers

Security headers melindungi klien di sisi browser:

Security headers middleware
func securityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        w.Header().Set("Content-Security-Policy",
            "default-src 'self'")
        w.Header().Set("Strict-Transport-Security",
            "max-age=31536000; includeSubDomains")
        w.Header().Set("X-Content-Type-Options", "nosniff")
        w.Header().Set("X-Frame-Options", "DENY")
        w.Header().Set("Referrer-Policy", "no-referrer")
        next.ServeHTTP(w, req)
    })
}

w.Header().Set("Content-Security-Policy", "default-src 'self'") mengatur sumber konten yang diizinkan browser. HSTS (Strict-Transport-Security) memaksa koneksi HTTPS untuk semua kunjungan berikutnya. Empat nilai yang wajib diingat: Content-Security-Policy mengurangi XSS, Strict-Transport-Security memaksa HTTPS, X-Frame-Options: DENY mencegah clickjacking, dan nosniff mencegah browser menebak tipe MIME.

CSRF dan Body Limit

Proteksi CSRF

Untuk mutasi state di aplikasi web, pastikan request berasal dari halaman kalian:

Validasi origin untuk mutasi
if req.Method == http.MethodPost ||
    req.Method == http.MethodPut ||
    req.Method == http.MethodDelete {
    origin := req.Header.Get("Origin")
    if origin != "" && origin != appOrigin {
        http.Error(w, "origin tidak dikenali",
            http.StatusForbidden)
        return
    }
}

Pengecekan Origin adalah lapisan CSRF dasar untuk API JSON. Untuk form klasik, pertimbangkan token CSRF per session. req.Header.Get("Origin") memberi tahu dari mana permintaan berasal.

Batasi Ukuran Body

Cegah request raksasa menghabiskan memory:

Body limit middleware
func limitBody(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
        req.Body = http.MaxBytesReader(w, req.Body, 1<<20)
        next.ServeHTTP(w, req)
    })
}

http.MaxBytesReader(w, req.Body, 1<<20) membatasi body maksimal 1 MiB. Saat handler membaca body melebihi batas, operasi gagal dengan http: request body too large.

Rate Limiting

Batasi Frekuensi Request

Rate limiting
r.Use(middleware.ThrottleBacklog(
    100,   // konteks aktif maksimal
    1000,  // backlog maksimal
    30*time.Second,
))

middleware.ThrottleBacklog(100, 1000, 30*time.Second) menolak request saat 100 request aktif dan antrian 1000 penuh selama 30 detik. Untuk limit berbasis IP per menit, pasangkan dengan Redis seperti di episode 19.

Validasi Input dan Pencegahan Injection

Validasi Terpusat

Jangan percaya input — validasi sebelum dipakai:

Validasi input
func validateUser(u User) error {
    if u.Name == "" {
        return NewAPIError(http.StatusBadRequest, "nama wajib diisi")
    }
    if !validEmail(u.Email) {
        return NewAPIError(http.StatusBadRequest, "email tidak valid")
    }
    return nil
}

NewAPIError(http.StatusBadRequest, ...) menolak input sejak awal dengan pesan yang jelas — lebih baik tolak di edge daripada bermasalah di database.

Cegah SQL Injection dan SSRF

SQL injection sudah tercegah oleh query parameterized ($1, $2) seperti episode 9. Untuk SSRF, jangan pernah membiarkan user mengontrol URL yang di-request server:

Pencegahan SSRF
allowedHosts := map[string]bool{
    "api.internal.example.com": true,
}
 
host := chi.URLParam(req, "host")
if !allowedHosts[host] {
    http.Error(w, "host tidak diizinkan",
        http.StatusForbidden)
    return
}

allowedHosts[host] membatasi host yang boleh diakses server. Selalu validasi terhadap allowlist — SSRF sering muncul dari URL yang dibentuk dari input user tanpa pemeriksaan.

RealIP dan X-Forwarded-For

Jangan Percaya Header Langsung

Header X-Forwarded-For bisa dipalsukan klien. pakai middleware.RealIP yang hanya memercayai proxy yang dikenal:

Pasang RealIP
r.Use(middleware.RealIP)

middleware.RealIP mengambil IP asli dari header proxy dan menimpanya ke req.RemoteAddr. Tanpa middleware ini, log dan rate limiting memakai IP yang bisa dipalsukan — celah umum pada aplikasi di belakang proxy. Pasang RealIP sebelum middleware lain yang membutuhkan IP, seperti logging dan rate limit.

Penutup

Inti yang harus dibawa pulang:

  • CORS dengan rs/cors: daftarkan origin spesifik, bukan wildcard.
  • Security headers: CSP, HSTS, X-Frame-Options, dan nosniff.
  • Proteksi CSRF dasar dengan pemeriksaan header Origin.
  • http.MaxBytesReader membatasi ukuran body request.
  • middleware.ThrottleBacklog menahan lonjakan beban.
  • Validasi input sejak edge; allowlist host untuk cegah SSRF.
  • middleware.RealIP mencegah pemalsuan X-Forwarded-For.

Di episode 15 selanjutnya kita mengamankan transportasi: HTTPS, reverse proxy, dan advanced networking — TLS manual, Let's Encrypt dengan autocert dan ACME, HTTP/2, reverse proxy di subrouter, serta integrasi dengan nginx dan Caddy.