Mengeraskan aplikasi FrankenPHP dari perspektif OWASP: memastikan HTTPS only dengan redirect otomatis, memasang security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options), menyembunyikan informasi server, dan meminimalkan eksposur worker.

Sejauh ini series ini membangun aplikasi FrankenPHP yang cepat dan teramati. Mulai episode ini, kita memastikan ia aman. Episode keamanan pertama membahas fondasi OWASP di level server: transport yang terenkripsi penuh, security headers yang menyelamatkan dari kelas-kelas serangan tertentu, dan kebersihan informasi yang bocor ke publik.
Mengapa penting? Banyak serangan web (XSS, clickjacking, MIME sniffing) tidak perlu menembus kode aplikasi — cukup diblokir oleh header yang benar di pinggir server. FrankenPHP/Caddy memberi kalian tempat yang sempurna untuk memasang tameng ini: sekali konfigurasi, seluruh rute terlindungi.
Automatic HTTPS (episode 10) sudah mengamankan traffic; tugas kita sekarang memastikan tidak ada satu pun request yang lolos dalam HTTP. Caddy melakukan redirect HTTP ke HTTPS secara otomatis saat automatic HTTPS aktif:
http://domain → 308 → https://domain.Untuk memastikan perilaku ini eksplisit, tulis secara gamblang di Caddyfile:
kaliansite.com {
# redirect HTTP -> HTTPS otomatis (default Caddy)
root * public/
encode zstd br gzip
php_server
}Warning
Di development, SERVER_NAME=":80" mematikan automatic HTTPS beserta redirect-nya. Pastikan value tersebut tidak pernah bocor ke produksi — periksa env var per environment (episode 11).
headerDirective header menambahkan atau mengganti response header untuk seluruh site. Ini tempat ideal untuk security headers:
kaliansite.com {
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
Permissions-Policy "camera=(), microphone=(), geolocation=()"
-Server
-X-Powered-By
}
root * public/
php_server
}Mari bedah masing-masing:
| Header | Melindungi dari |
|---|---|
Strict-Transport-Security (HSTS) | Downgrade attack HTTP → HTTPS |
X-Content-Type-Options: nosniff | MIME sniffing yang bisa memuat HTML sebagai script |
X-Frame-Options: DENY | Clickjacking (embedding situs di iframe) |
Referrer-Policy | Kebocoran URL sensitif via Referer |
Permissions-Policy | Penyalahgunaan API browser (kamera, mic, geolokasi) |
-Server / -X-Powered-By | Menyembunyikan identitas server |
Baris -Server dan -X-Powered-By adalah sintaks penghapusan — Caddy menghapus header tersebut dari response, sehingga penyerang tidak tahu versi server/stack yang dipakai.
CSP adalah header paling ampuh melawan XSS: ia membatasi sumber resource yang boleh dimuat halaman. Contoh ketat untuk aplikasi tanpa eksternal script:
header {
Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'"
}default-src 'self' — semua resource defaultnya hanya dari domain sendiri.script-src 'self' — script hanya dari domain sendiri (blokir CDN yang tidak dikenal).style-src 'self' 'unsafe-inline' — style internal diizinkan.img-src 'self' data: — gambar dari domain sendiri dan data URI.Caution
CSP yang terlalu ketat bisa memutuskan fitur (misal inline script library, WebSocket, atau Mercure di episode 18). Uji di staging dengan mode report dulu (Content-Security-Policy-Report-Only) sebelum mengaktifkan penuh di produksi.
Worker mode mengekspos memori proses — memperkecil permukaan serangan berarti membatasi apa yang bisa memicu eksekusi kode:
2019): siapa pun yang mengaksesnya bisa membaca config dan restart worker. Batasi hanya ke jaringan internal/monitoring..env, backup, dan direktori storage/ harus di luar root.request_body_timeout (episode 13) memutus slow POST; atur batas upload via php_ini upload_max_filesize dan post_max_size.Contoh hardening upload:
{
frankenphp {
php_ini upload_max_filesize 20M
php_ini post_max_size 25M
}
}
kaliansite.com {
root * public/
php_server {
request_body_timeout 60s
}
}Setelah konfigurasi terpasang, verifikasi dengan curl:
curl -sI https://kaliansite.com | rg -i "strict-transport|content-security|x-frame|x-content|server:"Output harus menampilkan header yang kita pasang, dan tidak boleh ada Server: yang membocorkan versi.
includeSubDomains memaksa semua subdomain HTTPS; pastikan tidak ada subdomain yang hanya HTTP.connect-src harus mengizinkan endpoint real-time (tambahkan wss:///origin Mercure).upload_max_filesize atau request_body_timeout yang kepotong — periksa log.Pada episode 14 ini, kalian telah mengeraskan aplikasi FrankenPHP di level transport dan header.
Inti yang harus dibawa pulang:
SERVER_NAME=":80" tidak bocor ke produksi.nosniff, X-Frame-Options, Referrer-Policy, Permissions-Policy.Server/X-Powered-By; tutup port admin; batasi upload.Di episode 15 selanjutnya kita membahas aspek keamanan operasional: CVE & security patch management — studi kasus CVE-2026-45062, verifikasi rilis dengan gh attestation, dan pola update tanpa downtime. Sampai jumpa di episode 15!