Belajar Curl - Production Readiness & Security Hardening
Series/Belajar Curl/Episode 21
Episode 21 of 23

Belajar Curl - Production Readiness & Security Hardening

Pada episode ini kita akan menyiapkan curl untuk produksi: verifikasi TLS tanpa jalan pintas, pengelolaan rahasia yang aman, timeout dan retry yang terukur, kebiasaan update yang disiplin, serta checklist keamanan untuk backend mulai dari SSRF, redirect, audit log, hingga pemantauan transfer.

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

Pendahuluan

Di episode 18 kalian belajar membaca kegagalan, dan di episode 20 kalian melihat bahwa curl dan libcurl bisa hidup di dalam aplikasi. Sekarang tibalah pertanyaan yang paling penting: apakah request kalian aman untuk produksi? Di laptop, sebuah flag yang ceroboh hanya membuat request kalian sendiri gagal. Di server produksi — atau di dalam backend yang melayani pengguna — kesalahan yang sama bisa menjadi lubang keamanan yang nyata.

Konsep kuncinya: setiap flag curl adalah keputusan keamanan. Default curl sudah cukup aman, tetapi banyak kebiasaan "biar cepat selesai" — mematikan verifikasi TLS, menulis password di command line, tanpa timeout — yang justru menciptakan celah. Episode 21 ini adalah checklist hardening: kebiasaan yang wajib, teknik yang benar, dan jebakan yang harus kalian hindari.

TLS Selalu Diverifikasi

Verifikasi sertifikat adalah satu-satunya hal yang memastikan kalian berbicara dengan server yang benar, bukan penipu di tengah jalan. Sejak episode 12 kalian tahu curl melakukannya secara default — dan di episode 18 kita menegaskan untuk tidak pernah mematikannya dengan -k.

anti-pattern.sh
# JANGAN lakukan ini di produksi
curl -k https://api.example.com/secure

Alih-alih mematikan verifikasi, perbaiki apa yang bermasalah. Perbarui CA bundle sistem agar mengenali CA baru:

cacert-explicit.sh
curl --cacert /etc/ssl/certs/ca-certificates.crt https://api.example.com/secure

Jika kalian menulis client yang perlu membuktikan identitasnya sendiri ke server (mutual TLS), gunakan pasangan sertifikat dan kunci kalian:

mtls.sh
curl --cert client.pem --key client-key.pem https://api.example.com/secure

Satu lagi keputusan yang sering diabaikan: batasi versi protokol. --tlsv1.2 mencegah koneksi jatuh ke TLS lawas yang sudah rapuh, dan --tls-max 1.3 memastikan kalian tidak menerima versi yang lebih tua dari yang diizinkan. Default curl memang masuk akal, tetapi menegaskan batasnya menghapus ambiguitas dari konfigurasi.

Warning

-k / --insecure bukan sekadar "kurang rapi" — itu membuka pintu untuk man-in-the-middle. Siapapun di jalur jaringan kalian (ISP, proxy, jaringan wifi publik, penyerang) bisa menyisipkan sertifikat palsu dan membaca seluruh isi request. Jika sebuah endpoint memaksa kalian memakai -k, curigai endpoint itu lebih dulu — bukan kunci yang harus dibuang.

Rahasia Tidak Pernah di Argumen Perintah

Kesalahan paling umum di dunia nyata adalah menulis kredensial langsung di command line. Masalahnya bukan hanya riwayat shell — isi argumen sebuah proses terlihat oleh semua user lewat ps selama proses itu berjalan. Di CI, command line bahkan tercatat di log pipeline.

jangan-begini.sh
# Password muncul di ps, riwayat shell, dan log CI
curl -u arman:sandirahasia https://api.example.com/me

Solusi yang benar adalah memisahkan kredensial dari command. Opsi paling sederhana: environment variable, yang tidak pernah muncul di ps:

env-token.sh
curl -u "$API_USER:$API_PASS" https://api.example.com/me

Untuk autentikasi berbasis kata sandi ke banyak host, .netrc adalah solusi yang rapi — curl membacanya saat dipanggil dengan --netrc, tanpa kredensial di argumen mana pun:

netrc.txt
machine api.example.com
login arman
password sandirahasia
netrc-usage.sh
curl --netrc-file ~/.api-netrc https://api.example.com/me

Important

File .netrc menyimpan kata sandi dalam teks polos, jadi izinnya wajib 600 (chmod 600 ~/.api-netrc) agar hanya pemiliknya yang bisa membacanya. Jangan pernah meng-commit file ini ke repository, dan jika perlu, hasilkan isinya dari secret manager saat proses deploy — bukan menyimpannya sebagai file statis.

Timeout, Retry, dan Kecepatan Transfer

Request produksi tanpa timeout adalah biang keladi skrip yang menggantung dan koneksi database yang meledak. Setiap request harus punya batas:

hardened-timeout.sh
curl --silent --show-error --fail-with-body \
  --connect-timeout 5 --max-time 30 \
  --retry 3 --retry-delay 2 --retry-all-errors \
  https://api.example.com/orders

Mari bedah keputusan di balik setiap flag:

  • --connect-timeout 5 — menyerah setelah 5 detik jika koneksi tidak terbentuk. Ini mencegah skrip menggantung saat host tidak terjangkau.
  • --max-time 30 — batas total seluruh transfer. Ini melindungi dari server yang menjawab lambat tapi tidak pernah menyerah.
  • --retry 3 --retry-delay 2 --retry-all-errors — mencoba ulang transfer yang gagal dengan jeda, sambil tetap punya batas agar tidak menjadi loop selamanya.
  • --silent --show-error — meredam progress meter, tapi tetap menampilkan pesan error.
  • --fail-with-body — keluar non-zero untuk status 4xx/5xx, sehingga skrip bisa mendeteksi kegagalan HTTP, bukan hanya kegagalan transfer.

Satu lapisan lagi untuk transfer yang "berjalan tapi berhenti": --speed-limit dan --speed-time memutus koneksi yang melambat di bawah ambang tertentu. Download yang macet diam-diam selama berjam-jam bukan lagi teka-teki — dengan pasangan flag ini, curl menganggapnya gagal dan retry (atau keluar) sesuai kebijakan kalian.

Selalu di Versi Stabil Terbaru

Rilis bulanan curl (dibahas di episode 19) memiliki satu konsekuensi yang tidak bisa dihindari: perbaikan keamanan datang cepat, dan kalian yang harus mengambilnya. curl tidak memperbarui dirinya sendiri — tidak ada auto-update. Versi yang terpasang di server kalian adalah versi yang bertanggung jawab atas keamanan transfer kalian.

Jadikan pemeriksaan versi bagian dari rutinitas:

cek-versi-terbaru.sh
curl --version

Di distro Debian/Ubuntu cukup apt update && apt upgrade curl; di RHEL/Fedora pakai dnf update curl. Meski terlihat sepele, kebiasaan update inilah yang membuat celah CVE tertutup tepat waktu. Jika kalian memakai curl/libcurl di dalam aplikasi (episode 20), perbarui bersamaan dengan dependensi lainnya — binding yang terpasang lama sering menempel pada versi libcurl yang sudah ketinggalan. Dan di sisi sebaliknya: jangan asal memasang versi terbaru di server produksi tanpa menguji — tapi jangan juga mengabaikan pembaruan keamanan berbulan-bulan. Stabilitas dan keamanan adalah keseimbangan, bukan pilihan salah satu.

Checklist Keamanan untuk Backend

Ketika curl/libcurl hidup di dalam backend, permukaan ancamannya berbeda — dan lebih berbahaya. Berikut empat item yang wajib masuk checklist.

Hindari SSRF

Server-Side Request Forgery (SSRF) terjadi ketika aplikasi memakai input pengguna untuk menentukan URL yang di-request server. Penyerang bisa mengarahkan server kalian ke http://169.254.169.254/ — alamat metadata cloud — atau ke service internal yang tidak seharusnya terjangkau dari luar. Sebelum curl/libcurl menyentuh URL, lakukan validasi: allowlist host yang diizinkan, dan blokir alamat private, loopback, serta link-local.

guard-ssrf.sh
HOST=$(printf '%s' "$1" | sed -E 's#^https?://##; s#/.*$##')
case "$HOST" in
    127.*|10.*|192.168.*|169.254.*) echo "URL ditolak" >&2; exit 1 ;;
esac
curl --silent --fail "$1"

Guard di atas adalah contoh sederhana; di produksi, validasi harus dilakukan di dalam aplikasi, bukan hanya di shell. Aturan emasnya: server tidak boleh diminta mengambil URL yang bisa dikendalikan pengguna tanpa penyaringan yang ketat.

Batasi Redirect

Redirect yang tidak diawasi bisa membawa request kalian ke mana pun — termasuk ke host yang tidak terduga. Jika request kalian mengikuti redirect (-L), pasang batas dan periksa tujuan akhirnya:

redirect-terbatas.sh
curl -L --max-redirs 3 https://api.example.com/login

Selain --max-redirs, pertimbangkan --proto-redir untuk membatasi protokol yang boleh diikuti saat redirect — misalnya menolak downgrade dari https ke http. Jika logika aplikasi kalian bergantung pada URL tujuan, validasi ulang setelah redirect, bukan hanya di URL awal.

Audit Log Request

Setiap request produksi harus meninggalkan jejak. Catat host tujuan, status code, timing, dan exit code — tanpa mencatat token atau body yang sensitif. Dengan -w dari episode 18, satu baris log lengkap bisa dihasilkan tanpa tool tambahan:

audit-log.sh
curl -sS -o /dev/null \
  -w "host=%{url_effective} code=%{http_code} total=%{time_total}s size=%{size_download}\n" \
  https://api.example.com/health >> /var/log/api-health.log

Log ini menjawab pertanyaan "apa yang terjadi kemarin pukul 02:00?" dalam satu detik — jauh lebih berharga daripada menebak dari ingatan. Jangan lupa log juga exit code curl (non-zero) secara eksplisit, karena itu sinyal bahwa transfer tidak pernah selesai.

Pantau Kecepatan dan Error Transfer

Log hanya berguna jika ada yang membacanya. Jadikan metrik transfer bagian dari monitoring: waktu total per request, jumlah error per menit, dan ukuran transfer. Pola yang sehat: lonjakan time_total atau munculnya exit code 28 (timeout) secara berulang adalah alarm pertama sebelum outage sungguhan. Skrip pemantauan yang memakai --fail-with-body akan gagal dengan jelas saat layanan bermasalah — dan itu justru yang kalian inginkan dari alarm.

Penutup

Episode 21 menutup sisi keamanan dengan lima pilar: verifikasi TLS tanpa kompromi, rahasia yang tidak pernah menyentuh argumen perintah, timeout dan retry yang terukur, kebiasaan update yang disiplin, serta checklist backend — SSRF, redirect, audit log, dan pemantauan transfer.

Inti yang harus dibawa pulang: keamanan curl bukan soal fitur, tapi soal kebiasaan. Default-nya sudah aman; tugas kalian adalah tidak merusaknya demi kenyamanan, dan menegaskan batas-batasnya secara eksplisit.

Di episode 22 — episode terakhir — kita akan menutup seluruh perjalanan: ekosistem, best practice, dan refleksi akhir dari 23 episode Belajar Curl. Sampai jumpa!