Keamanan Website: Praktik Terbaik Lapis demi Lapis (2026)

Poin penting

Keamanan website yang efektif dibangun berlapis: kunci domain dan DNS (registrar lock, DNSSEC, CAA), wajibkan TLS modern dengan HSTS, kirim serangkaian HTTP security header yang ketat, hash kata sandi dengan Argon2id yang dilengkapi MFA dan rate limit, validasi input serta terapkan kontrol akses di server, pin dan audit dependensi, tutup setiap port yang tidak Anda layani, dan simpan log yang cukup untuk menyadari adanya pembobolan. Setiap praktik di bawah ini disertai konfigurasi persisnya dan cara gratis untuk memverifikasi bahwa praktik itu benar-benar berjalan, karena kontrol yang belum pernah diuji sama saja dengan kontrol yang tidak Anda miliki.

Periksa sekarang

Keamanan website dalam enam lapisan: domain dan DNS, TLS, header HTTP, aplikasi, dependensi, dan server
Keamanan website dalam enam lapisan: domain dan DNS, TLS, header HTTP, aplikasi, dependensi, dan server
Mulai membaca
  1. Apa Itu Praktik Terbaik Keamanan Website?
  2. Tumpukan Keamanan Web: Enam Lapisan yang Harus Dilindungi
  3. Lapisan 1: Kunci Domain dan DNS
  4. Lapisan 2: HTTPS dan TLS yang Dikonfigurasi dengan Benar
  5. Lapisan 3: Header Keamanan HTTP (Security Headers)
  6. Lapisan 4: Autentikasi yang Tahan Credential Stuffing
  7. Sesi, Cookie, dan CSRF
  8. Injection dan XSS: Validasi Input, Encode Output
  9. Broken Access Control: Risiko Nomor Satu
  10. Lapisan 5: Dependensi dan Software Supply Chain
  11. Lapisan 6: Hardening Server (Port, Patch, Secret, Backup)
  12. Autentikasi Email: SPF, DKIM, dan DMARC
  13. Log, Pantau, dan Bersiap Menghadapi Pembobolan
  14. Uji: Scanner, Pentest, dan Pemeriksaan Berkelanjutan
  15. Checklist Keamanan Website
  16. Pemetaan ke OWASP Top 10:2025
  17. FAQ Keamanan Website

Apa Itu Praktik Terbaik Keamanan Website?

Praktik terbaik keamanan website adalah serangkaian kontrol yang menjaga website atau aplikasi web agar tidak diambil alih, di-deface, dipakai untuk menyerang pengunjungnya sendiri, atau datanya dikuras diam-diam. Praktik ini bukan satu produk atau satu pengaturan. Ini adalah tumpukan keputusan yang dimulai dari registrar domain, lalu berlanjut ke DNS, TLS, header HTTP yang dikirim server Anda, kode yang menangani login dan input, paket pihak ketiga yang menjadi fondasi aplikasi Anda, server itu sendiri, dan terakhir log yang memberi tahu Anda ketika ada yang tidak beres.

Alasan berpikir berlapis adalah karena penyerang pun berpikir demikian. Laporan Verizon 2026 Data Breach Investigations Report, yang mencakup lebih dari 22.000 insiden pembobolan dari November 2024 hingga Oktober 2025, menemukan bahwa 31% pembobolan dimulai dari kerentanan perangkat lunak yang dieksploitasi, naik dari 20% setahun sebelumnya dan untuk pertama kalinya melampaui kredensial curian (13%), sementara phishing stabil di 16%. Ransomware muncul di 48% pembobolan, naik dari 44%. Satu patch yang terlewat, satu API key yang bocor, atau satu halaman admin tanpa rate limiting sudah cukup. Tidak ada kontrol dalam panduan ini yang eksotis; website yang dibobol biasanya adalah yang melewatkan dasar-dasar di satu lapisan sambil memoles lapisan lain.

Panduan ini disusun dari luar ke dalam. Setiap praktik memberi tahu Anda mengapa penting, apa persisnya yang harus dikonfigurasi, dan cara memverifikasinya dengan perintah atau alat gratis seperti Pemeriksaan Header HTTP atau Pemeriksaan Sertifikat SSL, karena pengaturan yang Anda yakini aktif tetapi tidak pernah dikonfirmasi tidak melindungi apa pun.

Cek security header website

Tumpukan Keamanan Web: Enam Lapisan yang Harus Dilindungi

Setiap serangan terhadap website mendarat di salah satu dari enam lapisan. Tabel di bawah ini adalah peta untuk sisa panduan ini: apa yang ada di setiap lapisan, bagaimana lapisan itu biasanya diserang, dan pemeriksaan gratis mana yang memastikan pertahanan Anda benar-benar terpasang.

LapisanYang dilakukan penyerang di siniPraktik utamaVerifikasi dengan
1. Domain dan DNSMembajak domain, mengubah nameserver, mengambil alih subdomain yang menggantung (dangling), mendapatkan sertifikat palsuRegistrar lock, MFA, DNSSEC, CAA, audit record usangPencarian WHOIS, Cek Kesehatan DNS, Pencari Subdomain
2. Transport (TLS)Menurunkan koneksi ke HTTP (downgrade), melucuti enkripsi, mengeksploitasi cipher lama, sertifikat kedaluwarsaTLS 1.2+, HSTS (preload opsional), perpanjangan otomatisPemeriksaan Sertifikat SSL
3. Header HTTPMenyisipkan skrip (XSS), membingkai situs untuk clickjacking, menebak (sniffing) tipe konten, membocorkan referrerCSP, frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyPemeriksaan Header HTTP
4. AplikasiCredential stuffing, injection, kontrol akses yang rusak (broken access control), CSRF, upload yang tidak amanArgon2id + MFA + rate limit, query berparameter, otorisasi di sisi server, cookie SameSiteCode review, ZAP, Penguji Kekuatan Kata Sandi
5. DependensiPaket yang diracuni, CVE yang sudah diketahui di library, pipeline CI yang disusupiLockfile, audit, versi yang di-pin, SBOM, token dengan hak akses minimumnpm audit, Dependabot, Trivy
6. Server dan operasionalPort terbuka, kredensial default, patch yang terlewat, tanpa backup, tanpa logFirewall, SSH hanya dengan kunci, patching, backup 3-2-1, logging terpusatPemeriksa Port, Pemeriksaan Daftar Hitam IP

Kerjakan dari atas ke bawah. Lapisan 1 sampai 3 adalah konfigurasi yang bisa Anda selesaikan dalam satu sore, dan langsung melindungi semua halaman sekaligus. Lapisan 4 sampai 6 adalah kebiasaan berkelanjutan yang perlu menjadi bagian dari proses code review dan deployment Anda.

Lapisan 1: Kunci Domain dan DNS

Semua hal lain dalam panduan ini berasumsi Anda masih menguasai domain Anda. Jika penyerang bisa login ke registrar Anda atau mengubah nameserver, mereka bisa mengarahkan trafik Anda ke mana saja, mendapatkan sertifikat yang valid atas nama domain Anda, dan membaca setiap email yang dikirim kepada Anda, tanpa satu baris pun kode aplikasi Anda sempat berjalan. Karena itu, keamanan domain dan DNS adalah praktik terbaik keamanan website yang pertama, dan hampir seluruhnya berupa konfigurasi.

Mulailah dengan pencarian WHOIS pada domain Anda sendiri dan pastikan tiga hal: kode statusnya mencakup clientTransferProhibited, tanggal kedaluwarsanya masih lebih dari setahun lagi, dan registrarnya memang registrar tempat Anda punya akun. Cukup sering domain bisnis ternyata masih berada di akun registrar milik mantan kontraktor. Panduan pencarian WHOIS kami menjelaskan setiap kode status yang akan Anda temui.

Registrar Lock, MFA, dan Pengingat Masa Berlaku

Aktifkan registrar lock (disebut juga transfer lock) agar domain tidak bisa dipindahkan ke registrar lain tanpa Anda membukanya secara eksplisit, lalu aktifkan autentikasi multi-faktor (MFA) pada akun registrar itu sendiri. Akun registrar adalah sasaran phishing favorit justru karena satu login mengendalikan semua yang ada di bawahnya. Gunakan kunci keamanan fisik (hardware key) atau aplikasi autentikator, bukan SMS, di mana pun registrar mengizinkannya.

Setel domain agar diperpanjang otomatis dengan metode pembayaran yang tidak akan kedaluwarsa, dan tetap tambahkan pengingat kalender 60 hari sebelum tanggal kedaluwarsa. Domain yang lewat masa berlaku tidak langsung hilang pada hari kedaluwarsa, tetapi setelah masa tenggang dan masa penebusan habis (hingga sekitar 80 hari untuk .com) domain itu dihapus, dan layanan drop-catch mendaftarkannya dalam hitungan detik setelah dilepas. Pembelinya mewarisi email Anda, trafik Anda, dan semua login OAuth yang mempercayai domain Anda.

  • Registry lock (penguncian manual di tingkat registry yang dilakukan lewat jalur terpisah/out-of-band) layak dibayar lebih untuk domain yang menjadi tumpuan bisnis; penguncian ini mencegah perubahan nameserver bahkan jika akun registrar berhasil dibobol.
  • Pisahkan perannya. Orang yang membayar domain, akun yang memilikinya, dan penyedia DNS masing-masing harus terdokumentasi dan tidak terikat pada kotak surat satu karyawan.
  • Aktifkan privasi WHOIS agar detail kontak Anda tidak menjadi peta bagi pelaku phishing, dan gunakan alamat peran yang dipantau, seperti domains@, pada akun tersebut.

Tandatangani Zona dengan DNSSEC

DNSSEC menandatangani zona DNS Anda agar resolver dapat mendeteksi jawaban palsu. Tanpanya, penyerang yang bisa meracuni cache resolver dapat mengirim pengunjung Anda ke server palsu sementara browser mereka tetap menampilkan nama domain Anda. Sebagian besar penyedia DNS terkelola (Cloudflare, Route 53, Google Cloud DNS, dan banyak registrar) mengaktifkannya dengan satu sakelar; satu-satunya langkah manual adalah mempublikasikan record DS di registrar Anda. Verifikasi dengan dig, atau dengan Cek Kesehatan DNS, yang memeriksa record DS dan tanda tangannya:

bash
dig +dnssec +short yourdomain.com A
# A signed zone returns the record AND an RRSIG line:
# 203.0.113.10
# A 13 2 3600 20270115000000 20261225000000 34505 yourdomain.com. Kx3f...==

dig +short yourdomain.com DS
# A DS record at the parent zone proves the chain of trust is complete
# 2371 13 2 6A1B...C9

Batasi Penerbitan Sertifikat dengan CAA

Record CAA (RFC 8659) memberi tahu otoritas sertifikat (CA) mana saja yang boleh menerbitkan sertifikat untuk domain Anda. Setiap CA publik wajib memeriksanya sebelum menerbitkan sertifikat, sehingga record CAA menutup pintu bagi penyerang yang berhasil mengelabui validasi domain di CA lain. Tiga record sudah mencakup kasus umum: siapa yang boleh menerbitkan, siapa yang boleh menerbitkan sertifikat wildcard, dan ke mana permintaan yang ditolak harus dilaporkan:

dns
yourdomain.com.  CAA 0 issue "letsencrypt.org"
yourdomain.com.  CAA 0 issuewild ";"
yourdomain.com.  CAA 0 iodef "mailto:security@yourdomain.com"

Audit Record Usang: Subdomain Takeover

Pengambilalihan subdomain (subdomain takeover) terjadi ketika sebuah record DNS masih menunjuk ke layanan yang sudah Anda hentikan: CNAME ke situs GitHub Pages yang sudah dihapus, aplikasi Azure, bucket S3, atau hostname vendor SaaS. Siapa pun bisa mendaftarkan target yang ditinggalkan itu lalu menyajikan konten di old-app.yourdomain.com atas nama Anda, lengkap dengan sertifikat yang valid. Ini temuan yang rutin di program bug bounty karena tidak ada yang ingat record itu masih ada.

Jalankan domain Anda lewat Pencari Subdomain: alat ini mencari di dua layanan log certificate transparency, Cert Spotter (sertifikat saat ini) dan crt.sh (semua sertifikat sejak 2013), mencoba 1.000 nama umum, me-resolve setiap nama secara langsung, menandai CNAME yang menggantung, dan menunjukkan host atau CDN mana yang menjalankan masing-masing. Hapus setiap record yang targetnya mengembalikan NXDOMAIN atau halaman “no such app” milik penyedia; Pencarian DNS mengonfirmasi satu nama. Ulangi tiap kuartal, dan jadikan penghapusan record DNS bagian dari proses penghentian layanan apa pun.

Certificate transparency juga merupakan sistem peringatan dini Anda: Cert Spotter dan pemantauan CT milik Cloudflare bisa mengirim email setiap kali ada CA yang menerbitkan sertifikat untuk domain Anda. Sertifikat yang tidak terduga sering kali menjadi tanda pertama yang terlihat dari pembobolan DNS atau registrar.

Lapisan 2: HTTPS dan TLS yang Dikonfigurasi dengan Benar

HTTPS bukan lagi praktik terbaik, melainkan standar dasar; browser menandai halaman HTTP biasa sebagai “Tidak aman”. Google juga mengumumkan bahwa mulai Chrome 154 (Oktober 2026) browser akan bertanya sebelum membuka situs publik mana pun lewat HTTP biasa (Google). Hal yang masih membedakan situs yang aman dari situs yang sekadar terenkripsi adalah versi TLS yang Anda terima, apakah HTTP masih bisa dipakai untuk menjangkau Anda, dan apakah perpanjangan sudah cukup otomatis untuk bertahan dari pemangkasan masa berlaku sertifikat yang dimulai pada Maret 2026.

Minimal TLS 1.2, Utamakan TLS 1.3

TLS 1.0 dan 1.1 secara resmi dinyatakan usang (deprecated) oleh RFC 8996 pada 2021, dan tidak ada browser saat ini yang masih menegosiasikannya. Nonaktifkan keduanya di server, utamakan TLS 1.3 (yang membuang semua cipher yang diketahui lemah dan menyelesaikan handshake dalam satu kali round trip), dan pertahankan TLS 1.2 hanya dengan cipher suite AEAD seperti ECDHE-ECDSA-AES128-GCM-SHA256 atau ECDHE-RSA-CHACHA20-POLY1305.

Dua baris yang penting saat Anda menguji dari luar: protokol yang dinegosiasikan, dan Verify return code: 0, yang berarti seluruh rantai sertifikat tervalidasi. Sertifikat intermediate yang hilang adalah penyebab umum laporan “jalan di Chrome, gagal di curl dan Android”; panduan kami tentang rantai sertifikat SSL menunjukkan cara memperbaikinya, dan Pemeriksaan Sertifikat SSL langsung menandai rantai yang tidak lengkap. Berikut pemeriksaan yang dijalankan terhadap dnsrobot.net pada 27 Oktober 2026, lalu tes apakah server menolak TLS 1.1:

bash
echo | openssl s_client -connect dnsrobot.net:443 -servername dnsrobot.net 2>/dev/null \
  | grep -E 'Protocol|Cipher|Verify return'

# New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
# Protocol: TLSv1.3
# Verify return code: 0 (ok)

# Is TLS 1.1 refused? SECLEVEL=0 lets OpenSSL 3 and later offer it at all
openssl s_client -connect example.com:443 -servername example.com -tls1_1 \
  -cipher 'DEFAULT:@SECLEVEL=0' </dev/null 2>&1 | grep -E 'alert|Cipher is'

# Refused, as it should be:  ...tlsv1 alert protocol version...
#                            New, (NONE), Cipher is (NONE)
# Still accepted (fix it):   New, TLSv1.0, Cipher is ECDHE-ECDSA-AES128-SHA
#   (TLSv1.0 is the cipher's version; the handshake was TLS 1.1)

Daftar cipher adalah tempat konfigurasi hasil salin-tempel menjadi usang. Alih-alih menulisnya manual, buat blok server yang direkomendasikan saat ini untuk nginx, Apache, Caddy, atau HAProxy dengan Mozilla SSL Configuration Generator dan pilih profil “Intermediate” kecuali Anda harus mendukung klien yang sangat lama.

HSTS: Jangan Biarkan Browser Memakai HTTP Lagi

Mengalihkan HTTP ke HTTPS saja tidak cukup. Permintaan pertama yang dibuat pengunjung ke http://yourdomain.com tetap dikirim dalam teks biasa, dan penyerang di jaringan yang sama bisa menjawabnya lebih dulu sebelum redirect Anda. HTTP Strict Transport Security (RFC 6797) mengatasi masalah ini: begitu browser pernah melihat header tersebut, browser akan menulis ulang setiap URL http:// untuk domain Anda menjadi https:// sebelum mengirim apa pun.

Gunakan max-age minimal satu tahun (31536000 detik) dan tambahkan includeSubDomains setelah setiap subdomain melayani HTTPS. Mendaftar preload di hstspreload.org, yang menanamkan domain ke Chrome, Firefox, Safari, dan Edge, bersifat opsional: pengelola daftar itu sendiri kini menyatakan HSTS direkomendasikan tetapi preload tidak, karena Chrome dan Safari sudah meningkatkan navigasi ke HTTPS dan keluar dari daftar butuh waktu berbulan-bulan. Verifikasi header dengan Pemeriksaan Header HTTP, yang menilai HSTS dengan tes Mozilla HTTP Observatory.

http
Strict-Transport-Security: max-age=31536000; includeSubDomains

Sertifikat 47 Hari: Otomatiskan Perpanjangan Sekarang

Ballot SC-081 dari CA/Browser Forum memangkas masa berlaku maksimum setiap sertifikat TLS publik secara bertahap. Pemangkasan pertama berlaku sejak 15 Maret 2026, sehingga sertifikat apa pun yang Anda beli atau perpanjang hari ini sudah dibatasi 200 hari, dan pada 2029 sertifikat perlu diganti kira-kira setiap enam minggu:

Tanggal berlakuMasa berlaku maksimum sertifikatPenggunaan ulang validasi domain
Sebelum 15 Maret 2026398 hari398 hari
15 Maret 2026200 hari200 hari
15 Maret 2027100 hari100 hari
15 Maret 202947 hari10 hari

Perpanjangan manual tidak akan sanggup mengikuti jadwal ini. Praktik terbaiknya adalah penerbitan yang sepenuhnya otomatis melalui ACME: Let's Encrypt atau Google Trust Services lewat certbot, acme.sh, Caddy, atau sertifikat otomatis bawaan Cloudflare, Vercel, Netlify, dan sebagian besar panel hosting. Uji jalur perpanjangan sebelum Anda membutuhkannya (certbot renew --dry-run untuk certbot); kegagalan yang perlu diwaspadai adalah record CAA atau aturan firewall yang ditambahkan sejak perpanjangan terakhir dan kini memblokir validasi. Apa pun yang Anda gunakan, pantau juga tanggal kedaluwarsa dari luar: Pemeriksaan Sertifikat SSL menampilkan sisa hari, dan sertifikat yang kedaluwarsa mengubah setiap kunjungan menjadi peringatan browser satu halaman penuh.

Lapisan 3: Header Keamanan HTTP (Security Headers)

Security header adalah instruksi yang diberikan server Anda kepada browser tentang apa yang boleh dan tidak boleh dilakukan dengan halaman Anda: skrip mana yang boleh berjalan, apakah halaman boleh di-frame, apakah browser boleh menebak tipe konten, dan apa yang harus dikatakannya kepada situs lain tentang dari mana pengunjung datang. Semuanya tanpa biaya, berlaku untuk semua halaman sekaligus, dan memblokir seluruh kelas serangan. Ini juga lapisan yang sebagian besar situs kerjakan setengah benar, itulah sebabnya Pemeriksaan Header HTTP menilainya dengan tes Mozilla HTTP Observatory. Berikut yang dikirim github.com pada 27 Oktober 2026, dipangkas menjadi security header saja (script-src-nya menyebut satu host aset dan satu hash skrip, tanpa 'unsafe-inline'):

bash
curl -sI https://github.com/ | grep -iE 'strict-transport|content-security|x-frame|x-content-type|referrer-policy'

strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; ... frame-ancestors 'none'; ... script-src github.githubassets.com 'sha256-6AKuI+cDd1MoUL1u4eqrA9PXmnPAkOB4h7421hPUUm0='; ...

Tujuh Header yang Wajib Dikirim Setiap Situs

Berikut nilai yang sebaiknya dituju pada situs pada umumnya. Dalam penilaian Mozilla HTTP Observatory, yang dipakai Pemeriksaan Header HTTP kami, CSP yang hilang memotong 25 poin, HSTS atau perlindungan framing yang hilang masing-masing 20, sedangkan nosniff yang hilang 5; Referrer-Policy dan COOP menambah poin bonus selama skor masih 90 atau lebih. Permissions-Policy tidak dinilai (hanya browser Chromium yang membacanya), tetapi tetap layak diatur.

HeaderNilai yang direkomendasikanYang dicegah
Strict-Transport-Securitymax-age=31536000; includeSubDomainsDowngrade protokol, pencurian cookie melalui HTTP
Content-Security-Policyscript-src berbasis nonce dengan 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'Cross-site scripting (XSS), injeksi data, clickjacking
X-Content-Type-OptionsnosniffMIME sniffing yang mengubah file upload menjadi skrip yang bisa dieksekusi
Referrer-Policystrict-origin-when-cross-originBocornya URL lengkap (token, kata kunci pencarian) ke pihak ketiga
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=()Skrip pihak ketiga yang diam-diam memakai API browser yang sensitif
X-Frame-OptionsDENY (fallback lama untuk frame-ancestors)Clickjacking di browser tanpa CSP Level 2
Cross-Origin-Opener-Policysame-originSerangan lintas jendela melalui window.opener

Content Security Policy Tanpa Merusak Situs

Content Security Policy adalah pertahanan paling efektif terhadap XSS karena mencegah skrip sisipan berjalan bahkan ketika ada bug injeksi. Masalahnya, kebijakan yang ketat akan merusak skrip inline atau tag pihak ketiga yang terlupakan. Pendekatan modern, yang direkomendasikan Google dan didokumentasikan di MDN, adalah kebijakan berbasis nonce: server membuat nonce acak untuk setiap respons, memasangnya pada setiap tag script yang memang sengaja dirender, dan browser menolak semua yang lain.

'strict-dynamic' adalah yang membuat kebijakan ini praktis: skrip yang memiliki nonce boleh memuat skrip lain (analitik, tag manager, widget) tanpa harus memasukkan masing-masing ke allowlist, sementara token https: dan 'unsafe-inline' diabaikan oleh browser modern dan hanya berfungsi sebagai fallback untuk browser lama. Terapkan dulu dengan Content-Security-Policy-Report-Only, pantau laporan pelanggaran selama seminggu, lalu beralih ke mode enforce. Framework seperti Next.js, Rails, dan Django punya dukungan nonce bawaan; situs statis bisa memakai script-src berbasis hash sebagai gantinya.

http
Content-Security-Policy:
  script-src 'nonce-r4nd0m1z3dV4lu3' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';
  frame-ancestors 'none';
  form-action 'self';
  report-to csp-endpoint

<!-- Only scripts carrying the nonce run; strict-dynamic lets them load their own dependencies -->
<script nonce="r4nd0m1z3dV4lu3" src="/app.js"></script>

Kebijakan allowlist seperti script-src 'self' https://cdn.example.com lebih baik daripada tidak ada sama sekali, tetapi endpoint JSONP atau library lama apa pun di host yang masuk allowlist bisa dipakai untuk menembusnya. Jika Anda belum bisa memakai nonce, setidaknya atur object-src 'none' dan base-uri 'none', yang langsung menutup dua celah bypass yang umum.

Clickjacking: frame-ancestors dan X-Frame-Options

Clickjacking memuat situs Anda secara tak terlihat di dalam halaman penyerang dan mengelabui pengunjung agar mengklik tombol yang tidak bisa mereka lihat. frame-ancestors 'none' di CSP (atau 'self' jika Anda menyematkan halaman Anda sendiri) mencegahnya di semua browser saat ini, dan X-Frame-Options: DENY menangani browser yang lebih lama. Jika Anda sengaja menyediakan widget yang bisa disematkan, kecualikan hanya path tersebut dan hanya untuk origin yang membutuhkannya; panduan X-Frame-Options kami menjelaskan aturan server yang tepat dan error "refused to connect" yang akan Anda temui saat pengujian.

nosniff, Referrer-Policy, Permissions-Policy, dan COOP

X-Content-Type-Options: nosniff menghentikan browser dari menebak-nebak Content-Type, yang menjadi penyebab "gambar" unggahan pengguna yang berisi HTML berubah menjadi halaman yang bisa dieksekusi. Referrer-Policy: strict-origin-when-cross-origin (default di browser saat ini, tetapi tetap atur secara eksplisit) hanya mengirim origin Anda ke situs lain, sehingga token reset kata sandi dan kueri pencarian di URL tetap privat. Permissions-Policy menonaktifkan fitur browser yang tidak Anda pakai, sehingga skrip pihak ketiga yang disusupi tidak bisa membuka kamera atau membaca lokasi. Cross-Origin-Opener-Policy: same-origin memutus tautan window.opener ke halaman yang Anda buka, yang memblokir satu kelas serangan lintas jendela.

Header yang perlu dihapus juga penting: Server dan X-Powered-By mengiklankan versi perangkat lunak yang persis kepada pemindai kerentanan, dan X-XSS-Protection sudah usang serta bisa menimbulkan bug di browser lama, jadi setel ke 0 atau hapus. Pendeteksi CMS menunjukkan apa yang bisa diketahui siapa saja tentang stack dan versinya dari halaman itu sendiri.

Atur header sekali saja di edge (CDN, reverse proxy, atau middleware framework), bukan per halaman. Di Next.js, itu adalah file proxy atau middleware; di nginx, blok add_header dalam konteks server; di Apache, Header always set. Lalu jalankan ulang Pemeriksaan Header HTTP setelah setiap deploy, karena versi framework baru atau pengaturan CDN bisa diam-diam menghilangkan salah satunya.

Lapisan 4: Autentikasi yang Tahan Credential Stuffing

Penyerang jarang menebak kata sandi satu per satu. Mereka memutar ulang miliaran pasangan email dan kata sandi yang bocor dari situs lain (credential stuffing) dan mem-phishing sisanya. Karena itu, praktik terbaik autentikasi terdiri dari tiga bagian: simpan kata sandi sedemikian rupa sehingga kebocoran database tidak berarti kebocoran kata sandi, buat kata sandi curian tidak berguna jika berdiri sendiri, dan buat brute force terlalu lambat untuk berarti. OWASP menempatkan Authentication Failures (kegagalan autentikasi) di posisi A07 dalam OWASP Top 10:2025.

Hash Kata Sandi dengan Argon2id atau bcrypt

Jangan pernah menyimpan kata sandi, dan jangan pernah menyimpan hash cepat dari kata sandi. MD5, SHA-1, bahkan SHA-256 dirancang untuk cepat, sehingga tabel hash semacam itu yang bocor bisa diuji dengan miliaran tebakan per detik hanya dengan satu GPU. Gunakan fungsi hashing kata sandi yang lambat dan memory-hard dengan salt unik untuk setiap kata sandi. OWASP Password Storage Cheat Sheet merekomendasikan, secara berurutan:

  • Argon2id dengan memori minimal 19 MiB, 2 iterasi, dan tingkat paralelisme 1 (atau 46 MiB dengan 1 iterasi).
  • scrypt dengan N = 2^17, r = 8, p = 1 jika Argon2 tidak tersedia.
  • bcrypt dengan work factor 10 atau lebih (perhatikan batas input 72 byte; melakukan pre-hash pada kata sandi yang lebih panjang perlu kehati-hatian).
  • PBKDF2-HMAC-SHA256 dengan 600.000 iterasi, hanya jika kepatuhan FIPS mengharuskannya.
javascript
// Node.js with the argon2 package
import argon2 from "argon2";

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456, // KiB = 19 MiB
  timeCost: 2,
  parallelism: 1,
});

// Later, on login:
const ok = await argon2.verify(hash, submittedPassword);

Atur biayanya agar satu hash memakan waktu sekitar 100 hingga 250 ms di server login Anda. Pengguna asli tidak merasakannya, tetapi itu membatasi setiap inti CPU hanya pada segelintir tebakan per detik, dan bahkan kartu grafis kelas atas hanya pada ribuan, bukan miliaran. Hash ulang saat login berhasil setiap kali Anda menaikkan parameter, agar hash lama meng-upgrade dirinya sendiri.

Aturan Kata Sandi yang Benar-Benar Membantu (NIST SP 800-63B)

Aturan komposisi yang masih diterapkan kebanyakan situs (satu huruf besar, satu simbol, ganti setiap 90 hari) menghasilkan kata sandi yang mudah ditebak seperti Summer2026! dan mendorong orang untuk memakainya berulang kali. Panduan NIST SP 800-63B terbaru menggantinya dengan aturan yang mengukur hal yang benar-benar penting:

  • Minimal 8 karakter jika MFA juga diwajibkan, dan minimal 15 karakter untuk kata sandi yang dipakai tanpa faktor lain; izinkan panjang hingga setidaknya 64 karakter.
  • Tanpa aturan komposisi dan tanpa kewajiban rotasi berkala; wajibkan penggantian hanya jika ada bukti kata sandi telah disusupi.
  • Periksa setiap kata sandi baru terhadap daftar kebocoran (range API dari Have I Been Pwned memungkinkan hal ini tanpa mengirim kata sandinya) dan tolak kata sandi yang diketahui sudah bocor.
  • Izinkan paste dan pengelola kata sandi, terima spasi dan Unicode, dan berikan panduan yang membantu orang memilih kata sandi yang kuat, terutama tepat setelah Anda menolak satu kata sandi.

Penguji Kekuatan Kata Sandi kami menunjukkan perbedaan ukuran-ukuran ini dengan aturan lama: alat ini memperkirakan berapa lama kata sandi dibobol di bawah 8 serangan bernama, menunjukkan pola yang melemahkannya, dan memeriksanya terhadap data kebocoran tanpa mengirim kata sandinya, yang jauh lebih berguna daripada pesan merah “harus ada simbol”.

MFA dan Passkey

Autentikasi multi-faktor mengubah kata sandi curian menjadi jalan buntu. Tawarkan kepada semua pengguna dan wajibkan untuk peran admin, keuangan, dan dukungan pelanggan. Urutkan pilihannya berdasarkan ketahanan terhadap phishing: passkey dan kunci keamanan FIDO2 tidak bisa di-phishing karena kredensialnya terikat pada origin Anda yang asli; aplikasi autentikator (TOTP) sudah bagus; kode SMS lebih baik daripada tidak ada, tetapi bisa disadap melalui SIM swapping. Passkey didukung di semua browser dan sistem operasi saat ini dan menghilangkan kata sandi sepenuhnya, yang sekaligus menghapus credential stuffing sebagai sebuah kategori serangan.

Lindungi jalur pemulihan akun secermat login: kode pemulihan disimpan dalam bentuk hash, reset lewat email dengan token sekali pakai yang kedaluwarsa dalam 15 menit, dan tanpa pertanyaan keamanan.

Rate Limiting, Penguncian Akun, dan Pertahanan terhadap Bot

Terapkan rate limit pada endpoint login, registrasi, reset kata sandi, dan MFA per IP dan per akun, lalu kembalikan 429 Too Many Requests dengan header Retry-After begitu batasnya tercapai (panduan kami tentang HTTP error 429 membahas bagaimana klien seharusnya merespons). Kombinasikan dengan jeda yang makin panjang atau penguncian sementara setelah kegagalan berulang pada satu akun, serta CAPTCHA atau tantangan proof-of-work untuk endpoint yang menjadi sasaran serangan terdistribusi. Catat setiap login yang gagal beserta IP sumbernya agar pola serangan credential stuffing terlihat dalam hitungan menit, bukan bulan.

nginx
# nginx: 5 login attempts at once, then 1 every 12 seconds, per client IP
# (limit_req sends no Retry-After header; add one on your 429 page if clients need it)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

location = /api/login {
    limit_req zone=login burst=4 nodelay;
    limit_req_status 429;
    proxy_pass http://app;
}

Buat pesan error untuk "pengguna tidak dikenal" dan "kata sandi salah" sama persis, dan samakan juga waktu responsnya (lakukan hash pada kata sandi dummy jika pengguna tidak ada). Jika tidak, form login Anda sekaligus berfungsi sebagai API untuk enumerasi pengguna.

Sesi, Cookie, dan CSRF

Setelah login, cookie sesi adalah pengguna itu sendiri, jadi cookie ini layak mendapat perlindungan yang sama dengan kata sandi. Tiga atribut cookie dan satu prefiks nama melakukan sebagian besar pekerjaannya:

  • Secure berarti cookie tidak pernah dikirim melalui HTTP biasa, sehingga tidak bisa disadap di Wi-Fi publik.
  • HttpOnly membuat cookie tidak terlihat oleh JavaScript, sehingga bug XSS tidak bisa membacanya.
  • SameSite=Lax (atau Strict untuk panel admin) menjauhkan cookie dari permintaan POST lintas situs, yang menetralkan sebagian besar serangan CSRF.
  • Prefiks __Host- membuat browser menolak cookie kecuali cookie tersebut Secure, memiliki Path=/, dan tanpa atribut Domain, sehingga subdomain tidak bisa menimpanya.
http
Set-Cookie: __Host-session=9f1c7e2a...; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=28800

Aksi yang mengubah state tidak boleh bisa diakses lewat GET. Tautan seperti /account/delete?id=42 bisa dipicu oleh tag <img> di halaman mana pun yang dikunjungi pengguna, sebaik apa pun flag cookie Anda.

CSRF: Lapisan Kedua di Belakang SameSite

Cross-site request forgery (CSRF) mengelabui browser yang sedang login agar mengirim permintaan yang mengubah state ke situs Anda dari halaman lain. Cookie SameSite menghentikan kasus yang umum, tetapi tetap pasang pertahanan kedua pada setiap permintaan non-GET: token anti-CSRF per sesi di field tersembunyi atau header kustom, atau pemeriksaan bahwa header Origin (atau Sec-Fetch-Site) cocok dengan origin Anda sendiri. Sebagian besar framework (Django, Rails, Laravel, server action Next.js) melakukannya secara default; kesalahannya adalah menonaktifkan perlindungan ini untuk endpoint API lalu memanggil endpoint itu dari browser.

ID Sesi, Rotasi, dan JWT

Buat ID sesi dengan keacakan minimal 128 bit, rotasi ID saat login dan setiap kali hak akses berubah untuk menggagalkan session fixation, akhiri sesi setelah tidak ada aktivitas, dan beri pengguna tombol "keluar dari semua perangkat" yang membatalkan sesi di sisi server. Untuk JWT, buat masa berlakunya singkat (hitungan menit, dengan refresh token yang bisa dicabut), jangan pernah menyimpannya di localStorage tempat skrip apa pun bisa membacanya, dan perlakukan signing key yang bocor sebagai pembobolan penuh, karena setiap token yang pernah ditandatanganinya kini bisa dipalsukan.

Injection dan XSS: Validasi Input, Encode Output

Injection (A05:2025) dan cross-site scripting adalah kesalahan yang sama di tempat berbeda: data dari pengguna diserahkan ke interpreter (SQL, shell, kueri LDAP, halaman HTML) seolah-olah data itu kode. Solusinya pun sama di mana pun: pisahkan data dari kode, dan jangan pernah menyusun perintah dengan penggabungan string.

Query Berparameter, Bukan Menyusun String

Untuk SQL, gunakan prepared statement atau ORM yang membuatnya; database kemudian memperlakukan input sebagai nilai yang tidak akan pernah bisa mengubah struktur query. Aturan yang sama berlaku untuk perintah shell (kirim array argumen, jangan pernah string), filter NoSQL (tolak objek operator seperti {"$gt": ""} pada input pengguna), dan path file (resolve path-nya lalu pastikan tetap berada di bawah direktori yang dimaksud).

javascript
// Vulnerable: the input becomes part of the query text
const rows = await db.query(`SELECT * FROM users WHERE email = '${email}'`);

// Safe: the driver sends the value separately from the query
const rows = await db.query("SELECT * FROM users WHERE email = $1", [email]);

// Python / psycopg: same idea
cur.execute("SELECT * FROM users WHERE email = %s", (email,))

Encoding Output Menghentikan XSS

Cross-site scripting terjadi saat teks yang dikendalikan pengguna ditulis ke halaman tanpa di-encode sesuai konteks tempatnya berada. Mesin templating modern (React dan JSX, Vue, Jinja2, Blade, ERB) melakukan encoding secara default; XSS saat ini biasanya berasal dari celah pengecualiannya (escape hatch): dangerouslySetInnerHTML, v-html, |safe, innerHTML, serta penyusunan URL atau event handler inline dari data pengguna. Lakukan encoding sesuai konteks yang tepat, dan sanitasi HTML kaya (rich HTML) dengan library khusus seperti DOMPurify, bukan dengan regex.

Tempat data beradaEncode sebagaiContoh
Body HTMLEntitas HTML< menjadi &lt;, " menjadi &quot;
Atribut HTMLEntitas di dalam atribut berkutipSelalu beri tanda kutip pada atribut; encode " dan '
JavaScriptJangan menyisipkan ke dalam teks skrip; kirim data melalui atribut data- atau blok JSON <script type="application/json"></script> di dalam string menjadi \u003c/script\u003e
Parameter URLPercent-encodingencodeURIComponent(value)
Nilai CSSHindari sepenuhnya; pilih nama class dari allowlistJangan pernah menyisipkan input pengguna ke dalam style

SSRF, Upload File, dan Deserialisasi

Server-side request forgery (SSRF): jika server Anda mengambil URL yang diberikan pengguna (webhook, proxy gambar, pratinjau tautan), penyerang bisa mengarahkannya ke layanan internal atau ke endpoint metadata cloud 169.254.169.254 dan membaca kredensial. Resolve hostname terlebih dahulu, tolak rentang IP privat dan link-local, nonaktifkan redirect, dan tempatkan fetcher di segmen jaringan yang tidak bisa menjangkau apa pun di jaringan internal.

Upload file: validasi tipe file dengan memeriksa isinya, bukan ekstensinya atau Content-Type dari klien; terapkan batas ukuran; simpan file di luar web root atau di object storage dengan nama acak yang Anda buat sendiri; dan sajikan file dari origin terpisah dengan nosniff dan Content-Disposition: attachment jika memungkinkan. Jangan pernah membiarkan file upload berada di lokasi yang akan dieksekusi oleh web server.

Deserialisasi dan mass assignment: jangan pernah melakukan deserialisasi data yang tidak tepercaya dengan format yang bisa membuat instance class sembarang (serialisasi native Java, pickle di Python, unserialize di PHP, YAML dengan tag kustom); gunakan JSON dengan skema. Ikat body request ke allowlist field yang eksplisit agar pengguna tidak bisa mengirim POST "role": "admin" ke model yang kebetulan memiliki kolom tersebut.

Broken Access Control: Risiko Nomor Satu

Broken Access Control (kontrol akses yang rusak) menduduki posisi teratas OWASP Top 10 sejak 2021 dan tetap bertahan sebagai A01:2025. Ini bukan satu bug, melainkan kebiasaan: memeriksa siapa seseorang (autentikasi) tetapi lupa memeriksa apa yang boleh ia akses (otorisasi) di setiap permintaan. Bentuk klasiknya adalah insecure direct object reference (IDOR): GET /api/invoices/1042 berfungsi untuk pemilik invoice tersebut, dan juga untuk siapa pun yang mengganti angkanya.

  • Tolak secara default. Setiap route memerlukan aturan eksplisit yang memberikan akses; aturan yang tidak ada berarti 403, bukan 200.
  • Terapkan di server, per objek. Menyembunyikan tombol di UI bukanlah kontrol akses. Setiap operasi baca dan tulis harus memastikan pengguna saat ini memiliki atau diizinkan mengakses record spesifik tersebut, termasuk di endpoint massal, fitur ekspor, dan background job.
  • Gunakan ID yang tidak bisa ditebak jika membantu (UUID), tetapi jangan pernah mengandalkannya: menyamarkan bukanlah otorisasi.
  • Perketat CORS. Access-Control-Allow-Origin: * dengan kredensial, atau memantulkan Origin apa pun yang dikirim request, sama saja dengan menyerahkan API Anda ke website mana pun yang dikunjungi pengguna.
  • Nonaktifkan directory listing, blokir .git, .env, file backup, dan file konfigurasi di tingkat web server, serta jauhkan panel admin dari internet publik atau lindungi dengan MFA dan allowlist IP.
  • Terapkan rate limit dan catat kegagalan otorisasi. Lonjakan 403 dari satu sesi adalah tanda serangan enumerasi yang sedang berlangsung.
javascript
// Express: ownership check on every object access
app.get("/api/invoices/:id", requireAuth, async (req, res) => {
  const invoice = await Invoice.findById(req.params.id);
  if (!invoice || invoice.ownerId !== req.user.id) {
    return res.status(404).end(); // 404, not 403: don't confirm the record exists
  }
  res.json(invoice);
});

Lapisan 5: Dependensi dan Software Supply Chain

Sebagian besar kode dalam aplikasi web pada umumnya adalah kode yang Anda unduh, bukan yang Anda tulis. Itulah sebabnya Software Supply Chain Failures debut di A03 dalam OWASP Top 10 2025, dan mengapa eksploitasi kerentanan melampaui phishing dan kredensial curian dalam DBIR 2026. Pada September 2025, satu maintainer yang terkena phishing membuat malware pencuri kripto masuk ke chalk, debug, dan 16 paket npm lain yang totalnya diunduh lebih dari dua miliar kali per minggu; setiap proyek yang menginstal versi yang tidak di-pin selama jendela itu menariknya secara otomatis.

  • Commit lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum) dan instal dengan npm ci di CI agar build bisa direproduksi dan rilis upstream baru tidak bisa menyelinap masuk tanpa ditinjau.
  • Scan terus-menerus: npm audit, pip-audit, bundler-audit, GitHub Dependabot atau Renovate untuk pembaruan, serta scanner container seperti Trivy atau Grype untuk lapisan OS.
  • Tunda upgrade non-keamanan beberapa hari (minimumReleaseAge di Renovate) agar rilis yang diracuni biasanya sudah ditarik sebelum Anda mengadopsinya, tetapi terapkan patch keamanan segera.
  • Pin action dan skrip pihak ketiga ke SHA commit di CI, dan gunakan Subresource Integrity (integrity="sha384-...") pada skrip apa pun yang Anda muat dari CDN publik.
  • Beri CI hak akses seminimal mungkin: token read-only jika memungkinkan, kredensial OIDC berumur pendek alih-alih secret berumur panjang, dan hak publikasi yang dibatasi hanya untuk job rilis.
  • Buat SBOM (CycloneDX atau SPDX) saat build agar Anda bisa menjawab "apakah kita terdampak?" dalam hitungan menit saat CVE sekelas Log4Shell berikutnya muncul.
bash
# Reproducible install + audit in CI
npm ci --ignore-scripts
npm audit --audit-level=high

# Pin a GitHub Action to a commit, not a floating tag
# uses: actions/checkout@v4                 <- can change underneath you
# uses: actions/checkout@<full-commit-sha>  # v4.2.2

# Subresource Integrity for a CDN script (hash from: openssl dgst -sha384 -binary lib.min.js | openssl base64 -A)
<script src="https://cdn.example.com/lib.min.js"
        integrity="sha384-<base64-hash>"
        crossorigin="anonymous"></script>

npm ci --ignore-scripts memblokir skrip saat instalasi yang dipakai sebagian besar malware npm untuk berjalan; setelah itu aktifkan kembali skrip hanya untuk segelintir paket yang memang membutuhkan langkah build.

Jika Anda menjalankan WordPress atau CMS lain, aturan yang sama berlaku untuk plugin dan tema, yang menjadi titik awal sebagian besar kasus pembobolan CMS. Selalu perbarui core dan setiap plugin, hapus yang tidak Anda pakai, dan periksa apa yang bisa diketahui scanner tentang versi Anda dengan Pendeteksi CMS.

Lapisan 6: Hardening Server (Port, Patch, Secret, Backup)

Lapisan aplikasi tidak ada artinya jika server di bawahnya menerima login SSH dengan kata sandi, menjalankan database di port publik, atau belum pernah di-patch sejak pertama kali dibangun. Praktik terbaik server memang membosankan, dan justru di situlah ransomware masuk.

Tutup Setiap Port yang Tidak Anda Layani

Web server publik membutuhkan port 80 dan 443 terbuka, serta SSH dari rentang IP Anda sendiri. Database (3306, 5432, 27017), Redis (6379), Elasticsearch (9200), panel admin, dan endpoint metrik sebaiknya hanya bind ke localhost atau jaringan privat. Periksa dari luar dengan Pemeriksa Port setelah setiap perubahan, karena itulah sudut pandang yang didapat penyerang, dan security group di cloud mudah salah dibaca.

bash
# Ubuntu: default-deny firewall, allow only web + SSH from your office range
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp
sudo ufw enable   # check your own IP is in that range first, or you lock yourself out

# SSH: keys only, no root password login, in a drop-in that sshd reads first
printf 'PasswordAuthentication no\nPermitRootLogin prohibit-password\n' \
  | sudo tee /etc/ssh/sshd_config.d/00-hardening.conf
sudo sshd -T | grep -E '^(passwordauthentication|permitrootlogin) '   # what sshd will really use
sudo systemctl reload ssh

Di Ubuntu dan Debian, sshd membaca file di /etc/ssh/sshd_config.d/ sebelum sisa sshd_config, dan untuk setiap pengaturan, nilai pertama yang dibacanya yang berlaku. Karena itu perintah di atas menulis drop-in bernama 00-hardening.conf: suntingan yang lebih bawah di file utama akan kalah dari drop-in image cloud yang berisi PasswordAuthentication yes. Konfirmasi hasilnya dengan sudo sshd -T sebelum logout. Di Pemeriksa Port, port yang dibuang firewall Anda tampil sebagai Terfilter (tanpa balasan), dan port yang tidak ada yang mendengarkan sebagai Tertutup: keduanya aman, yang perlu diperbaiki adalah Terbuka.

Patch Secara Terjadwal, Jauhkan Secret dari Kode

Aktifkan pembaruan keamanan otomatis (unattended) untuk sistem operasi, berlangganan milis keamanan untuk runtime dan framework Anda, dan perlakukan CVE kritis pada apa pun yang terhubung ke internet sebagai pekerjaan yang harus selesai hari itu juga. Jalankan layanan sebagai pengguna tanpa hak istimewa, di dalam container atau dengan sandboxing systemd, sehingga proses yang disusupi tidak bisa membaca seluruh mesin.

Secret (kata sandi database, API key, signing key) tidak boleh berada di repository, di layer image Docker, atau di JavaScript sisi klien. Muat secret dari environment variable yang disuntikkan saat deploy atau dari secrets manager, rotasi saat seseorang yang memiliki akses keluar, dan pindai riwayat repository dengan tool seperti gitleaks, karena kunci yang pernah di-commit sekali akan tetap dianggap bocor selamanya, bahkan setelah commit-nya dihapus.

Backup yang Tahan Ransomware, dan CDN di Depan Server

Ikuti aturan 3-2-1: tiga salinan, di dua media berbeda, satu di luar lokasi (off-site), dan jadikan setidaknya satu salinan immutable atau offline agar ransomware yang mencapai server tidak bisa ikut mengenkripsi backup. Enkripsi backup, sertakan database dan direktori upload, dan yang terpenting, uji proses restore secara terjadwal. Backup yang belum pernah dipulihkan hanyalah harapan, bukan rencana. Waktu pemulihan adalah faktor yang menentukan apakah sebuah insiden hanya menjadi gangguan layanan atau peristiwa yang mengakhiri perusahaan.

Pasang CDN atau WAF (Cloudflare, Fastly, AWS CloudFront dengan WAF, atau padanan dari penyedia hosting Anda) di depan origin. Ia menyerap DDoS volumetrik, menerapkan aturan terkelola untuk payload injeksi umum dan bot jahat, menyembunyikan IP origin Anda, dan memberi tempat untuk menerapkan rate limit dan aturan geografis tanpa menyentuh aplikasi. Lalu batasi firewall origin agar hanya rentang IP CDN yang bisa menjangkau port 443 secara langsung; jika tidak, penyerang tinggal melewatinya. Cek Hosting Website menunjukkan CDN mana yang berada di depan sebuah situs dan apa yang dikatakan bukti publik tentang host di belakangnya.

Autentikasi Email: SPF, DKIM, dan DMARC

Keamanan web mencakup email yang membawa reset kata sandi, faktur, dan balasan dukungan Anda. Tanpa SPF, DKIM, dan DMARC, siapa pun bisa mengirim surel sebagai billing@yourdomain.com; sejak Februari 2024 Google dan Yahoo mewajibkan ketiganya dari pengirim massal, dan sejak Mei 2025 Microsoft melakukan hal yang sama untuk Outlook.com. Set lengkapnya adalah tiga record TXT DNS:

dns
yourdomain.com.                    TXT  "v=spf1 include:_spf.google.com -all"
google._domainkey.yourdomain.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
_dmarc.yourdomain.com.             TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"

DMARC p=reject juga merupakan kontrol perlindungan merek: hanya inilah yang bisa mencegah kampanye phishing mencantumkan domain Anda yang persis di baris From. Laporan agregat (rua=) menunjukkan siapa yang sedang mencobanya.

Mulai DMARC di p=none untuk mengumpulkan laporan, lalu pindah ke p=quarantine dan kemudian p=reject setelah setiap pengirim sah (platform pemasaran, helpdesk, CRM) lolos alignment. Tambahkan record MTA-STS dan TLS-RPT untuk memaksa pengiriman terenkripsi ke server email Anda. Pada domain yang tidak pernah mengirim atau menerima email, publikasikan null MX (MX 0 .), v=spf1 -all, dan record DMARC dengan p=reject: null MX hanya menyatakan bahwa domain tidak menerima email, sedangkan SPF dan DMARC yang memungkinkan penerima menolak pemalsuan. Verifikasi setiap record dengan Pemeriksa Rekaman SPF, Pemeriksa DKIM, dan Pemeriksa DMARC, dan periksa IP pengirim Anda terhadap daftar blokir dengan Pemeriksaan Daftar Hitam IP jika deliverability turun.

Log, Pantau, dan Bersiap Menghadapi Pembobolan

Dua dari sepuluh kategori OWASP 2025 membahas apa yang terjadi setelah sebuah kesalahan: Security Logging and Alerting Failures (A09) dan kategori baru Mishandling of Exceptional Conditions (A10). Pembobolan pada umumnya masih tidak terdeteksi selama berbulan-bulan karena buktinya tidak pernah dicatat, atau sudah dicatat tetapi tidak ada yang melihatnya.

  • Catat event keamanan beserta konteksnya: setiap login yang berhasil maupun gagal, perubahan MFA, reset kata sandi, perubahan izin, penolakan kontrol akses, kegagalan validasi input, dan aksi admin, masing-masing dengan timestamp, ID pengguna, IP sumber, dan user agent.
  • Jangan pernah mencatat secret: kata sandi, token sesi, nomor kartu lengkap, API key. Samarkan di lapisan logging, bukan di setiap titik pemanggilan.
  • Kirim log keluar dari server ke penyimpanan terpusat (CloudWatch, Loki, Elastic, SIEM) dengan retensi minimal 90 hari, agar penyerang yang punya akses root tidak bisa menghapus jejaknya.
  • Pasang peringatan berdasarkan pola, bukan event tunggal: 50 login gagal dalam semenit, lonjakan 403 dari satu sesi, admin baru yang dibuat di luar jam kerja, sertifikat yang diterbitkan untuk domain Anda padahal tidak pernah Anda minta.
  • Fail closed: ketika pemeriksaan di hilir (layanan autentikasi, rate limiter, WAF) mengalami error, tolak request tersebut. A10 ada karena begitu banyak sistem justru memberikan akses ketika pemeriksaan yang seharusnya memblokir malah melempar exception.
  • Pantau dari luar: uptime, kedaluwarsa sertifikat, perubahan DNS, pencantuman di daftar blokir, dan regresi header. Jalankan ulang Pemeriksaan Sertifikat SSL, Pemeriksaan Header HTTP, dan Cek Kesehatan DNS (40 pengecekan untuk delegasi, nameserver, DNSSEC, dan SPF/DMARC) setelah setiap deploy.

Tulis Rencana Respons Insiden Sebelum Anda Membutuhkannya

Putuskan sebelumnya siapa yang siaga, cara merotasi setiap kredensial, cara menjadikan situs read-only, di mana backup yang bersih berada, dan regulator atau pelanggan mana yang harus diberi tahu dalam berapa jam (72 jam menurut GDPR). Jalankan latihan tabletop setahun sekali. Rencana yang sudah dilatih mengubah berhari-hari improvisasi menjadi sebuah checklist.

Publikasikan file security.txt di /.well-known/security.txt (RFC 9116) dengan baris Contact: dan tanggal Expires:, dua kolom yang wajib (kunci Encryption: bersifat opsional). Peneliti yang menemukan bug di situs Anda akan mencari di sana lebih dulu; tanpanya, mereka mungkin tidak menemukan siapa pun untuk dilapori.

Uji: Scanner, Pentest, dan Pemeriksaan Berkelanjutan

Setiap kontrol di atas bisa diverifikasi, dan verifikasinya sebaiknya diotomatiskan sebisa mungkin agar tidak tergerus seiring waktu. Berikut tangga yang masuk akal, dari yang gratis dan instan hingga yang berkala dan berbayar:

PemeriksaanToolSeberapa sering
Konfigurasi TLS, rantai sertifikat, masa berlakuPemeriksaan Sertifikat SSL, SSL Labs, testssl.shSetelah setiap perubahan sertifikat atau server; masa berlaku setiap hari
Security header dan CSPPemeriksaan Header HTTP, MDN HTTP ObservatorySetelah setiap deploy (masukkan ke CI)
Port terbukaPemeriksa Port, nmap dari luar jaringan AndaSetelah setiap perubahan firewall atau cloud
DNS, DNSSEC, autentikasi emailCek Kesehatan DNS, Pemeriksa DMARCBulanan, dan setelah setiap perubahan DNS
Subdomain usangPencari SubdomainSetiap kuartal dan setiap kali layanan dinonaktifkan
Dependensi yang diketahui rentannpm audit, Dependabot, TrivySetiap build
Celah di level kode (SAST)Semgrep, CodeQLSetiap pull request
Kerentanan web saat runtime (DAST)ZAP, NucleiMingguan terhadap staging
Otorisasi dan logika bisnisPenetration test manual atau program bug bountyTahunan, dan setelah fitur besar dirilis

Scanner andal dalam menemukan injection, masalah header, dan komponen usang, tetapi lemah dalam otorisasi dan logika bisnis, jadi anggarkan setidaknya satu pengujian oleh manusia per tahun untuk apa pun yang menangani uang atau data pribadi. Perbaiki berdasarkan tingkat keterpaparan: apa pun yang bisa dieksploitasi pengguna tanpa autentikasi dari internet harus didahulukan.

Checklist Keamanan Website

Salin ini ke README proyek atau issue tracker Anda. Setiap baris adalah salah satu praktik di atas, dirumuskan agar bisa ditandai selesai atau belum; kolom terakhir adalah buktinya.

LapisanPraktikSelesai jika
DomainRegistrar lock dan MFA di akun registrar; perpanjangan otomatis aktifWHOIS menampilkan clientTransferProhibited; masa berlaku masih lebih dari 12 bulan
DNSZona ditandatangani DNSSEC; record CAA hanya mencantumkan CA Andadig +dnssec mengembalikan RRSIG; record DS ada di zona induk
DNSTidak ada record CNAME atau A yang menggantung (dangling)Setiap hostname dari Pencari Subdomain mengarah ke sesuatu yang Anda kendalikan
TLSHanya TLS 1.2+, TLS 1.3 diutamakan, rantai sertifikat lengkap disajikanPemeriksaan Sertifikat SSL: rantai lengkap, TLS 1.0/1.1 ditolak
TLSHSTS dengan max-age satu tahun dan includeSubDomains (preload opsional)Pemeriksaan Header HTTP lolos tes HSTS
TLSPerpanjangan diotomatiskan lewat ACME; masa berlaku dipantaucertbot renew --dry-run berhasil; peringatan dipasang pada 14 hari
HeaderCSP (berbasis nonce), frame-ancestors, nosniff, Referrer-Policy, Permissions-PolicyNilai A atau A+ di Pemeriksaan Header HTTP
AutentikasiHashing Argon2id atau bcrypt; aturan kata sandi NIST; pemeriksaan daftar kebocoranSatu hash memakan waktu 100 hingga 250 ms; tanpa aturan komposisi
AutentikasiMFA ditawarkan ke semua pengguna, wajib untuk admin; passkey didukungLogin admin tidak mungkin tanpa faktor kedua
AutentikasiEndpoint login, reset, dan MFA dibatasi rate limit per IP dan per akunEnam percobaan cepat dari satu IP: yang keenam mengembalikan 429
SesiCookie __Host- dengan Secure, HttpOnly, SameSite; ID dirotasi saat loginAtribut cookie terlihat di DevTools; sesi lama tidak valid setelah login
InputQuery berparameter di semua tempat; output di-encode sesuai konteks; upload divalidasi berdasarkan isinyaTidak ada query hasil penyusunan string dalam pencarian kode; payload XSS tampil sebagai teks
Kontrol aksesRouting tolak-secara-default; pemeriksaan kepemilikan per objek; CORS ketatMemutar ulang ID pengguna lain mengembalikan 404 atau 403
DependensiLockfile di-commit; npm ci; audit di CI; action di-pin ke SHA; SRI pada skrip CDNBuild gagal jika ada CVE dengan tingkat keparahan tinggi
ServerHanya 80 dan 443 yang publik; SSH hanya dengan kunci; pembaruan keamanan otomatis; secret di env atau vaultPemeriksa Port menunjukkan 3306 dan 6379 tertutup atau terfilter, dan 22 juga bila dilihat dari luar rentang Anda sendiri
Backup3-2-1 dengan satu salinan immutable; restore sudah diujiUji restore terakhir yang berhasil bertanggal dalam 90 hari terakhir
EmailSPF -all, DKIM, DMARC p=reject, MTA-STSLolos Pemeriksa DMARC; laporan agregat berdatangan
MonitoringEvent autentikasi dan otorisasi dicatat secara terpusat; peringatan berbasis pola; pemantauan uptime, sertifikat, dan DNS dari luarPeringatan uji sudah dipicu dan diterima
ResponsRencana insiden tertulis; security.txt dipublikasikan; latihan tabletop sudah dijalankanRencana ditinjau dalam 12 bulan terakhir

Pemetaan ke OWASP Top 10:2025

OWASP Top 10 adalah daftar risiko aplikasi web yang paling banyak dikutip, dan edisi 2025-nya mengubah urutan serta memperkenalkan dua kategori baru. Jika klien, auditor, atau framework kepatuhan menanyakan bagaimana Anda menanganinya, inilah pemetaannya ke praktik-praktik dalam panduan ini:

OWASP Top 10:2025Praktik dalam panduan ini
A01 Broken Access ControlTolak secara default, pemeriksaan per objek, CORS ketat, penguncian panel admin
A02 Security MisconfigurationSecurity header, HSTS, port tertutup, header versi dihapus, directory listing dinonaktifkan
A03 Software Supply Chain Failures (baru)Lockfile, audit, action yang di-pin, SRI, SBOM, CI dengan hak akses minimum
A04 Cryptographic FailuresTLS 1.2+ dan 1.3, HSTS, Argon2id, pengelolaan secret, backup terenkripsi
A05 InjectionQuery berparameter, encoding output, CSP, validasi upload
A06 Insecure DesignThreat model per lapisan, default fail-closed, rate limiting sejak tahap desain
A07 Authentication FailuresAturan kata sandi NIST, pemeriksaan kebocoran, MFA dan passkey, rotasi sesi
A08 Software or Data Integrity FailuresSRI, dependensi yang ditandatangani dan di-pin, deserialisasi yang aman
A09 Security Logging and Alerting FailuresLogging terpusat, peringatan berbasis pola, pemantauan eksternal
A10 Mishandling of Exceptional Conditions (baru)Fail closed, respons error yang seragam, tanpa stack trace ke pengguna

ASVS (Application Security Verification Standard) dari OWASP mengubah materi yang sama menjadi checklist bernomor untuk audit. Level 1 adalah target yang realistis untuk situs publik apa pun; Level 2 untuk apa pun yang menangani data pribadi atau keuangan.

Cek security header situs Anda dalam hitungan detik

Pemeriksaan Header HTTP gratis dari DNS Robot menampilkan header respons URL mana pun persis seperti yang dikirim server dan menilai security header-nya dengan tes Mozilla HTTP Observatory, lengkap dengan perbaikan untuk setiap yang belum ada. Tanpa perlu mendaftar.

Sumber

  1. 2026 Data Breach Investigations Report, Verizon
  2. OWASP Top 10:2025, OWASP
  3. Password Storage Cheat Sheet, OWASP
  4. SP 800-63B-4: Authentication and Authenticator Management, NIST
  5. Ballot SC-081v3: reducing certificate validity and data reuse periods, CA/Browser Forum
  6. HTTPS by default, Google
  7. RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF

FAQ Keamanan Website

Apa saja praktik keamanan website yang paling penting?

Wajibkan HTTPS dengan TLS modern dan HSTS, kirim security header yang ketat (terutama Content Security Policy), hash kata sandi dengan Argon2id yang dilengkapi MFA dan rate limiting, gunakan query berparameter dan encoding output, terapkan kontrol akses di server untuk setiap objek, jaga dependensi tetap ter-patch dan di-pin, tutup port yang tidak dipakai, dan catat event keamanan secara terpusat. Kunci domain dan DNS terlebih dahulu, karena semua hal lain bergantung pada kendali Anda atas nama domain tersebut.

Apa itu OWASP Top 10 dan apakah masih relevan di 2026?

OWASP Top 10 adalah peringkat risiko keamanan aplikasi web paling kritis yang dikelola oleh komunitas. Edisi 2025 mencantumkan Broken Access Control, Security Misconfiguration, Software Supply Chain Failures, Cryptographic Failures, Injection, Insecure Design, Authentication Failures, Software or Data Integrity Failures, Security Logging and Alerting Failures, dan Mishandling of Exceptional Conditions. Daftar ini tetap menjadi acuan yang dirujuk sebagian besar audit, framework, dan klien.

Header keamanan HTTP apa saja yang harus dikirim setiap website?

Minimal: Strict-Transport-Security, Content-Security-Policy (termasuk frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, dan Permissions-Policy. X-Frame-Options: DENY adalah fallback lama untuk frame-ancestors, dan Cross-Origin-Opener-Policy: same-origin adalah tambahan yang murah. Hapus Server dan X-Powered-By agar scanner tidak bisa membaca versi software Anda.

Apakah HTTPS saja cukup untuk membuat website aman?

Tidak. HTTPS mengenkripsi lalu lintas antara browser dan server; ia tidak berbuat apa-apa terhadap injeksi, kontrol akses yang rusak, kata sandi lemah, dependensi yang rentan, atau port database yang terbuka. Itu lapisan dasar, dan HSTS membuatnya bertahan: setelah browser melihat headernya, ia tidak akan pernah lagi mengirim permintaan HTTP biasa ke domain Anda.

Bagaimana cara yang benar menyimpan kata sandi pengguna?

Jangan pernah dalam teks biasa dan jangan pernah dengan hash cepat seperti MD5 atau SHA-256. Gunakan Argon2id (memori 19 MiB, 2 iterasi) atau bcrypt dengan work factor 10 atau lebih, dengan salt unik untuk setiap kata sandi, disetel agar satu hash memakan waktu sekitar 100 hingga 250 ms. Periksa kata sandi baru terhadap daftar kebocoran dan wajibkan MFA untuk akun dengan hak istimewa.

Apa itu Content Security Policy dan apakah website saya membutuhkannya?

CSP adalah header HTTP yang memberi tahu browser sumber skrip, style, frame, dan resource lain mana saja yang boleh dimuat sebuah halaman. CSP berbasis nonce dengan 'strict-dynamic' menghentikan sebagian besar cross-site scripting bahkan ketika ada bug injeksi. Situs apa pun yang merender konten dari pengguna atau memuat skrip pihak ketiga sebaiknya memilikinya; mulailah dalam mode report-only dan beralih ke mode enforce setelah laporan pelanggarannya bersih.

Bagaimana cara mengecek keamanan website saya?

Jalankan pemeriksaan dari luar dulu: cek SSL untuk versi TLS, rantai, dan masa berlaku; cek header HTTP untuk security header; cek port untuk layanan yang terbuka; dan cek kesehatan DNS untuk DNSSEC dan SPF/DMARC. Lalu pindai dependensi dengan npm audit atau padanannya untuk stack Anda, jalankan ZAP terhadap salinan staging, dan uji kontrol akses secara manual dengan memutar ulang permintaan sebagai pengguna lain.

Mengapa masa berlaku sertifikat TLS makin pendek?

CA/Browser Forum memutuskan lewat pemungutan suara untuk memangkas masa berlaku maksimum sertifikat dari 398 hari menjadi 200 hari (15 Maret 2026), 100 hari (15 Maret 2027), dan 47 hari (15 Maret 2029), karena sertifikat yang lebih pendek membatasi kerusakan akibat kunci yang dicuri atau sertifikat yang salah terbit, serta mengurangi ketergantungan pada pencabutan (revocation). Dampak praktisnya, perpanjangan harus diotomatiskan dengan ACME.

Seberapa sering dependensi website harus diperbarui?

Terapkan patch keamanan segera setelah dirilis, idealnya dalam 24 jam untuk apa pun yang terhubung ke internet, dan jalankan audit otomatis di setiap build. Untuk pembaruan non-keamanan, jeda singkat beberapa hari lebih aman, karena rilis paket yang disusupi biasanya cepat ditarik; tool seperti Renovate bisa menerapkan jeda tersebut secara otomatis.

Apakah website kecil benar-benar diserang?

Ya, terus-menerus, karena serangan berjalan otomatis dan tidak memilih target berdasarkan ukuran. Scanner menyisir setiap alamat IP publik untuk mencari port terbuka dan kerentanan CMS yang sudah diketahui, dan tool credential stuffing mencoba kata sandi yang bocor di setiap form login yang ditemukannya. Situs kecil juga berharga sebagai host phishing, relay spam, atau pijakan untuk menyusup ke pelanggan yang lebih besar.

Tentang penulis

Shaik Vahid

Pendiri DNS Robot. Vahid bertahun-tahun bekerja di dukungan web hosting, memperbaiki domain, record DNS, sertifikat SSL, dan pengiriman email untuk pelanggan. Ia membangun alat-alat DNS Robot dan menulis panduan ini dari error yang benar-benar dialami orang.

Cek HTTP Header

Analisis header respons HTTP dan penilaian header keamanan