CSRF di Go
Tentu, mari kita bedah secara lengkap apa itu CSRF dan fungsi dari setiap bagian kode csrf.go
ini.
## Apa itu CSRF? 🤔
CSRF adalah singkatan dari Cross-Site Request Forgery. Ini adalah jenis serangan siber di mana penyerang menipu korban (pengguna yang sudah login di suatu website) untuk tanpa sadar mengirimkan permintaan berbahaya ke website tersebut.
Analogi Sederhana:
Bayangkan Anda memiliki rekening di Bank A dan sudah login di browser Anda. Sesi login Anda disimpan dalam bentuk cookie.
Kemudian, Anda membuka tab baru dan mengunjungi website jahat, Website B. Di Website B, ada sebuah tombol yang terlihat tidak berbahaya, misalnya "Klik untuk melihat kucing lucu". Saat Anda mengkliknya, di balik layar, Website B sebenarnya mengirimkan formulir tersembunyi ke Bank A untuk mentransfer uang dari rekening Anda.
Karena Anda masih login di Bank A (browser Anda secara otomatis menyertakan cookie login), Bank A mengira permintaan transfer itu sah dari Anda dan memprosesnya. Anda baru saja menjadi korban CSRF.
Singkatnya, penyerang "memalsukan" atau "menumpang" sesi login Anda untuk melakukan aksi atas nama Anda tanpa persetujuan Anda.
## Penjelasan Kode csrf.go
csrf.go
Kode ini menyediakan sebuah mekanisme perlindungan bawaan di Go untuk melawan serangan CSRF. Cara kerjanya adalah dengan memeriksa dari mana sebuah permintaan berasal sebelum memprosesnya.
### Komentar Awal dan struct CrossOriginProtection
Go
// CrossOriginProtection implements protections against [Cross-Site Request
// Forgery (CSRF)] by rejecting non-safe cross-origin browser requests.
// ...
type CrossOriginProtection struct {
bypass atomic.Pointer[ServeMux]
trustedMu sync.RWMutex
trusted map[string]bool
deny atomic.Pointer[Handler]
}
Komentar: Komentar di awal menjelaskan tujuan utama dari kode ini: melindungi dari CSRF dengan menolak permintaan cross-origin (dari situs lain) yang tidak aman.
CrossOriginProtection
: Ini adalahstruct
atau cetak biru utama yang menampung semua konfigurasi untuk perlindungan CSRF.bypass
: Menyimpan pola-pola URL yang diizinkan untuk melewati pemeriksaan keamanan. Menggunakanatomic.Pointer
agar aman diakses dari banyak request secara bersamaan (concurrency-safe).trustedMu
dantrusted
:trusted
adalah sebuahmap
(kamus) untuk menyimpan daftar origin (situs) yang dipercaya.trustedMu
(sync.RWMutex
) adalah "kunci" yang memastikan hanya satu proses yang bisa mengubah daftar ini pada satu waktu, sehingga aman dari race condition.deny
: Menyimpan sebuahHandler
khusus yang akan dijalankan jika sebuah request diblokir. Ini juga menggunakanatomic.Pointer
agar concurrency-safe.
### Fungsi-Fungsi Konfigurasi
Fungsi-fungsi ini digunakan untuk mengatur cara kerja perlindungan.
NewCrossOriginProtection()
Go
func NewCrossOriginProtection() *CrossOriginProtection { return &CrossOriginProtection{} }
Fungsi sederhana untuk membuat objek
CrossOriginProtection
baru yang kosong.AddTrustedOrigin(origin string)
Go
func (c *CrossOriginProtection) AddTrustedOrigin(origin string) error { // ... (validasi input) c.trustedMu.Lock() defer c.trustedMu.Unlock() // ... (menambahkan origin ke map trusted) }
Kegunaan: Untuk mendaftarkan situs lain sebagai situs yang dipercaya. Misalnya, jika website Anda
api.myapp.com
dan Anda ingin mengizinkan permintaan dariwebapp.myapp.com
, Anda akan menambahkanwebapp.myapp.com
sebagai trusted origin.AddInsecureBypassPattern(pattern string)
Go
func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) { // ... }
Kegunaan: Untuk membuat pengecualian berdasarkan pola URL. Misalnya, Anda mungkin ingin menonaktifkan perlindungan CSRF untuk endpoint
/api/public/
yang memang dirancang untuk bisa diakses dari mana saja. KataInsecure
ditambahkan untuk mengingatkan developer bahwa ini melonggarkan keamanan.SetDenyHandler(h Handler)
Go
func (c *CrossOriginProtection) SetDenyHandler(h Handler) { // ... }
Kegunaan: Untuk mengganti respons standar saat request diblokir. Secara default, server akan mengirimkan respons
403 Forbidden
. Dengan fungsi ini, Anda bisa menampilkan halaman error kustom atau mencatat log khusus.
### Logika Inti Pemeriksaan
Ini adalah bagian terpenting di mana pemeriksaan keamanan sebenarnya terjadi.
Check(req *Request)
Go
func (c *CrossOriginProtection) Check(req *Request) error { // ... }
Fungsi ini adalah otak dari perlindungan CSRF. Ia menjalankan serangkaian pemeriksaan:
Metode Aman: Jika metode request adalah
GET
,HEAD
, atauOPTIONS
, maka permintaan itu dianggap "aman" (tidak mengubah data di server) dan selalu diizinkan.Sec-Fetch-Site
Header: Ini adalah header modern yang dikirim oleh browser. Isinya memberitahu server asal-usul permintaan (same-origin
,cross-site
, dll.). Jika nilainyasame-origin
(dari situs yang sama), permintaan diizinkan. Jika nilainyacross-site
, permintaan akan ditolak (kecuali ada di daftar pengecualian).Origin
Header: JikaSec-Fetch-Site
tidak ada (mungkin karena browser lama), kode ini akan memeriksa headerOrigin
. Ia membandingkan nilaiOrigin
denganHost
dari request. Jika cocok, permintaan dianggapsame-origin
dan diizinkan.Pengecualian: Terakhir, fungsi
isRequestExempt
dipanggil untuk memeriksa apakah request cocok dengan pola bypass atau berasal dari origin yang terpercaya.
isRequestExempt(req *Request)
Go
func (c *CrossOriginProtection) isRequestExempt(req *Request) bool { // ... }
Fungsi pembantu yang memeriksa dua hal:
Apakah URL request cocok dengan salah satu pola yang didaftarkan di
AddInsecureBypassPattern
?Apakah header Origin dari request ada di dalam daftar trusted yang diatur via AddTrustedOrigin?
Jika salah satunya benar, fungsi ini mengembalikan true dan request diizinkan.
### Middleware Handler
Handler(h Handler)
Go
func (c *CrossOriginProtection) Handler(h Handler) Handler { return HandlerFunc(func(w ResponseWriter, r *Request) { if err := c.Check(r); err != nil { // ... (tolak request) return } h.ServeHTTP(w, r) }) }
Kegunaan: Ini adalah cara paling umum untuk menggunakan
CrossOriginProtection
. Fungsi ini bertindak sebagai middleware atau "pembungkus". Ia mengambil handler asli Anda (h
), lalu mengembalikannya dalam versi baru. Versi baru ini akan menjalankanc.Check(r)
terlebih dahulu.Jika
Check
gagal (mengembalikan error), request akan langsung ditolak dengan status403 Forbidden
.Jika
Check
berhasil, request akan diteruskan ke handler asli Anda untuk diproses seperti biasa.
Last updated