Keamanan

Audit Header Keamanan HTTP: CSP dan HSTS dengan Satu Curl

Audit Header Keamanan HTTP: CSP dan HSTS dengan Satu Curl

Enam header keamanan HTTP yang paling sering direkomendasikan ternyata sudah terpasang di toolkuy.com saat artikel ini disusun: Content-Security-Policy, Permissions-Policy, Referrer-Policy, Strict-Transport-Security, X-Content-Type-Options, dan X-Frame-Options. Respons yang diperiksa adalah HTTP/2 200 dari Cloudflare, dengan HSTS max-age=31536000 yang setara satu tahun dan includeSubDomains aktif. Yang belum beres bukan soal ada atau tidaknya header, melainkan isi CSP yang masih mengizinkan 'unsafe-inline' pada script-src dan style-src, sehingga sebagian manfaat proteksi XSS hilang.

TL;DR

  • Enam header keamanan utama terukur hadir pada respons https://toolkuy.com, semuanya dikirim lewat Cloudflare.
  • HSTS memakai max-age=31536000 detik atau satu tahun, plus includeSubDomains, tetapi tanpa arahan preload.
  • CSP sudah memakai object-src 'none', base-uri 'self', dan frame-ancestors 'self', tiga pengaman yang paling sering dilupakan.
  • Namun script-src dan style-src masih membawa 'unsafe-inline', yang melemahkan perlindungan terhadap injeksi skrip.
  • Audit header cukup satu perintah curl, dan hasilnya harus dibaca sebagai konfigurasi, bukan sebagai skor.

Header keamanan apa saja yang wajib ada di situs produksi?

Minimal ada empat yang dampaknya langsung terasa: HSTS untuk memaksa HTTPS, X-Content-Type-Options untuk mematikan MIME sniffing, X-Frame-Options atau frame-ancestors untuk mencegah clickjacking, dan Referrer-Policy untuk mengendalikan kebocoran URL. Dua tambahan yang makin penting adalah Content-Security-Policy sebagai lapisan utama mitigasi XSS dan Permissions-Policy untuk mematikan fitur peramban yang tidak dipakai. Daftar lengkap beserta contoh nilainya tersedia di OWASP Secure Headers Project.

Urutan prioritasnya bukan soal kelengkapan, melainkan soal risiko yang ditutup. Situs statis tanpa formulir mungkin tidak butuh CSP seketat aplikasi dengan login, tetapi tetap butuh HSTS dan nosniff. Sebaliknya, aplikasi dengan autentikasi butuh CSP yang ketat karena XSS di sana berarti pengambilalihan sesi.

HeaderNilai yang terukur di toolkuy.comFungsi utama
Strict-Transport-Securitymax-age=31536000; includeSubDomainsmemaksa HTTPS untuk satu tahun ke depan
Content-Security-Policydefault-src 'self'; object-src 'none'; frame-ancestors 'self'; script-src memuat 'unsafe-inline'membatasi sumber skrip, frame, dan objek
X-Content-Type-Optionsnosniffmencegah peramban menebak tipe berkas
X-Frame-OptionsSAMEORIGINmencegah halaman dibingkai situs lain
Referrer-Policystrict-origin-when-cross-originmenyembunyikan path saat lintas origin
Permissions-Policy8 fitur dimatikan, termasuk kamera, mikrofon, dan geolokasimenutup akses API peramban yang tidak dipakai

Bagaimana cara mengaudit header keamanan dalam satu perintah?

Cukup satu permintaan HEAD dengan curl, lalu saring baris yang relevan. Perintah berikut menghasilkan keluaran yang dipakai untuk menyusun tabel di atas, dijalankan pada 28 Oktober 2026 terhadap halaman utama.

curl -sS -I -L --max-time 15 https://toolkuy.com   | grep -iE '^(HTTP/|server:|strict|content-type|x-frame|x-content|referrer|permissions-policy|content-security|cache-control|cf-)'

Dua hal yang perlu diperhatikan saat membaca hasilnya. Pertama, nilai header yang dikirim CDN bisa berbeda dari yang dikonfigurasi di origin, jadi kalau pakai Cloudflare atau proksi lain, periksa juga konfigurasi di sisi edge. Kedua, urutan header tidak penting, tetapi keberadaan header pada respons final yang penting; Header yang hanya muncul di origin namun dihapus di edge tidak melindungi apa pun.

Seberapa kuat HSTS satu tahun tanpa preload?

max-age=31536000 detik berarti peramban mengingat perintah HTTPS selama satu tahun sejak kunjungan terakhir, dan includeSubDomains memperluasnya ke seluruh subdomain. Itu nilai yang wajar dan sudah memenuhi saran umum untuk produksi. Yang belum ada adalah arahan preload, sehingga domain belum bisa didaftarkan ke daftar preload peramban dan kunjungan pertama ke versi HTTP masih bisa terjadi sebelum header diterima.

Konsekuensi praktisnya kecil untuk situs yang seluruh tautannya sudah HTTPS, tetapi tetap relevan untuk serangan downgrade pada kunjungan pertama. Menambahkan preload bukan keputusan ringan: pendaftaran ke daftar preload berarti subdomain tertentu tidak bisa lagi memakai HTTP tanpa melalui proses pengeluaran dari daftar, dan mekanismenya diatur di RFC 6797 serta halaman dokumentasi MDN tentang HSTS.

Kenapa 'unsafe-inline' di CSP jadi masalah?

Karena 'unsafe-inline' mengizinkan skrip dan gaya yang ditulis langsung di dalam halaman, sehingga salah satu tujuan utama CSP, yaitu menolak skrip yang tidak dikenal, tidak lagi berjalan. Kalau penyerang berhasil menyisipkan tag skrip ke dalam HTML, peramban akan mengeksekusinya karena kebijakan memang mengizinkannya. Pada keluaran yang diperiksa, frasa itu muncul dua kali, pada script-src dan style-src.

Melepasnya membutuhkan perubahan di sisi aplikasi: skrip inline harus diganti dengan berkas eksternal, atau memakai nonce dan hash yang didukung CSP level 2 dan 3. Untuk situs yang dibangun dengan framework modern, langkah ini biasanya berarti mengonfigurasi build agar menyisipkan nonce pada setiap tag skrip. Dokumentasi MDN tentang CSP menjelaskan mekanisme nonce, hash, dan strict-dynamic secara rinci.

Apa lagi yang sering terlewat meski enam header utama sudah ada?

Yang paling sering terlewat adalah Cross-Origin-Opener-Policy dan Cross-Origin-Resource-Policy, dua header yang mengatur isolasi antar origin dan relevan ketika situs memuat sumber daya pihak ketiga. Header lain yang perlu dipertimbangkan adalah Cross-Origin-Embedder-Policy untuk fitur yang butuh isolasi penuh. Tidak semuanya wajib; keputusannya bergantung pada apakah situs memakai SharedArrayBuffer, high-resolution timer, atau embed pihak ketiga.

Selain header, ada lapisan yang tidak terlihat dari curl: masa berlaku sertifikat, konfigurasi TLS minimum, dan kebijakan rotasi kunci. Ketiganya tidak muncul di respons HTTP, sehingga audit header yang bersih tidak otomatis berarti konfigurasi TLS-nya benar. Untuk memeriksanya, gunakan alat uji TLS terpisah dan periksa juga konfigurasi di sisi CDN, karena negosiasi awal terjadi di sana.

Bagaimana memasang header ini di server sendiri?

Konfigurasinya bergantung pada proksi yang dipakai. Pada Caddy, blok header cukup ditulis sekali di dalam site block; pada nginx, setiap add_header perlu diulang di lokasi yang relevan karena perilaku pewarisannya tidak otomatis. Yang penting, uji hasilnya dengan curl setelah perubahan, bukan hanya membaca berkas konfigurasi.

header {
    Strict-Transport-Security "max-age=31536000; includeSubDomains"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "SAMEORIGIN"
    Referrer-Policy "strict-origin-when-cross-origin"
    Permissions-Policy "camera=(), microphone=(), geolocation=()"
    Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
}

Contoh di atas adalah titik awal, bukan nilai final. Setiap situs punya kebutuhan berbeda: yang memuat font dari CDN perlu menambahkan font-src, yang memakai analitik perlu menambahkan domainnya di script-src. CSP yang terlalu ketat akan merusak halaman, dan CSP yang terlalu longgar tidak melindungi apa pun, jadi perubahan harus diuji di lingkungan staging lebih dulu.

Bagaimana urutan migrasi CSP tanpa merusak situs?

Mulai dari mode laporan: kirim kebijakan yang diinginkan lewat Content-Security-Policy-Report-Only, kumpulkan pelanggaran, lalu perketat bertahap setelah pelanggaran itu nol. Pada respons toolkuy.com yang diukur, pelaporan sudah terpasang lewat report-uri /api/csp-report dan report-to csp-endpoint, jadi endpoint penerima laporan sudah tersedia dan bisa dipakai untuk menampung laporan dari kebijakan yang lebih ketat sebelum diberlakukan. Cara ini membuat kesalahan konfigurasi terlihat sebagai catatan, bukan sebagai halaman rusak bagi pengunjung.

Urutan yang biasanya aman adalah: kunci dulu default-src, lalu object-src dan base-uri, lalu frame-ancestors, baru setelah itu script-src dan style-src. Dua yang terakhir paling berisiko merusak tampilan karena hampir setiap halaman memuat skrip dan gaya. Melepas 'unsafe-inline' sebaiknya dilakukan paling akhir, setelah semua skrip inline dipindahkan ke berkas eksternal atau diberi nonce.

Setiap perubahan sebaiknya diikuti pengujian halaman yang paling kompleks, bukan hanya halaman utama. Halaman dengan formulir, peta, atau embed pihak ketiga biasanya yang pertama rusak ketika CSP diperketat, dan kerusakannya sering tidak terlihat sebagai error di konsol server karena pelanggaran CSP terjadi di peramban pengunjung.

Apakah header keamanan perlu berbeda antara halaman HTML dan API?

Ya, karena risikonya berbeda. Halaman HTML membutuhkan CSP dan X-Frame-Options untuk melindungi pengunjung, sedangkan respons API berbentuk JSON biasanya cukup dengan nosniff dan cache-control yang benar, karena tidak ada peramban yang merender isinya sebagai halaman. Mengirim CSP ketat pada respons API tidak merugikan, tetapi tidak menambah perlindungan yang berarti.

Yang justru penting pada API adalah memastikan respons error tidak membocorkan detail internal, dan memastikan header cache tidak membuat data sensitif tersimpan di proksi perantara. Pada keluaran yang diperiksa, cache-control bernilai public dengan s-maxage 600, nilai yang wajar untuk halaman publik tetapi tidak boleh dipakai untuk respons yang berisi data pengguna.

Setelah perubahan dipasang, verifikasi ulang dengan perintah yang sama seperti saat audit, dan lakukan pada beberapa path, bukan hanya halaman utama. Halaman artikel, halaman kategori, dan endpoint API bisa dilayani oleh aturan yang berbeda di proksi, sehingga header yang benar di beranda belum tentu ikut terkirim di tempat lain. Simpan keluaran sebelum dan sesudah perubahan sebagai pembanding, karena ingatan tentang nilai header sebelumnya cepat memudar dan perbandingan tertulis jauh lebih bisa dipercaya.

Satu hal terakhir yang perlu disiapkan saat memakai mode laporan: volume laporan pelanggaran. Kebijakan yang terlalu ketat pada situs yang memuat banyak skrip pihak ketiga bisa menghasilkan ribuan laporan per hari dari satu halaman populer, dan endpoint yang tidak dibatasi akan tumbuh menjadi beban tersendiri. Batasi jumlah laporan per permintaan, kelompokkan berdasarkan direktif yang dilanggar, dan tetapkan masa berlaku supaya data pelanggaran tidak menumpuk tanpa batas. Setelah kebijakan diberlakukan penuh, endpoint pelaporan tetap berguna untuk memantau regresi, jadi jangan buru-buru mematikannya begitu pelanggaran pertama sudah nol.

FAQ

Apakah semua situs wajib punya CSP?

Tidak wajib, tetapi sangat disarankan untuk situs yang memproses input pengguna atau menyimpan sesi login. Situs statis tanpa input tetap mendapat manfaat dari CSP sederhana dengan default-src 'self', karena membatasi sumber daya yang boleh dimuat.

Berapa nilai max-age HSTS yang dianjurkan?

Nilai umum untuk produksi adalah 31.536.000 detik atau satu tahun, dan itu yang terukur pada toolkuy.com. Nilai lebih pendek dipakai saat pengujian agar mudah dibatalkan jika ada subdomain yang masih memakai HTTP.

Apakah header keamanan memperlambat situs?

Dampaknya dapat diabaikan. Header hanya menambah beberapa ratus byte pada respons, dan nilainya biasanya dikirim dari cache edge. Yang berpengaruh pada performa adalah ukuran konten dan jumlah permintaan, bukan header keamanan.

Kenapa X-Frame-Options masih dipakai kalau CSP punya frame-ancestors?

Untuk kompatibilitas peramban lama. frame-ancestors sudah menggantikan fungsinya di peramban modern, tetapi mengirim keduanya tidak menimbulkan konflik dan tetap melindungi klien yang belum mendukung CSP. Nilai SAMEORIGIN berarti halaman hanya boleh dibingkai oleh origin yang sama.

Di mana dokumentasi resmi setiap header?

Ringkasan praktik terbaik ada di OWASP Secure Headers Project, penjelasan HSTS di MDN dan RFC 6797, sedangkan detail CSP ada di dokumentasi CSP MDN.

💬 Komentar (0)

Belum ada komentar. Jadilah yang pertama! 💬

Komentar akan muncul setelah moderasi.