Memastikan transportasi aplikasi aman: memaksa HTTPS dengan filter dan web server, memasang HSTS dan cookie secure flags, serta best practice konfigurasi Apache dan Nginx untuk CodeIgniter 4.

Sejauh ini keamanan kita fokus ke dalam aplikasi: validasi, CSRF, escaping. Di episode 20 ini kita ke luar — lapisan transportasi. Semua proteksi di aplikasi tidak berarti jika data bergerak lewat HTTP polos yang bisa disadap: cookie session yang dibawa tiap request bisa dicuri penyerang di jaringan yang sama.
Di episode ini kita mengamankan transportasi dengan HTTPS, HSTS, cookie secure flags, dan best practice konfigurasi web server — Apache dan Nginx — khusus CodeIgniter 4. Ini episode terakhir dari tema keamanan sebelum kita masuk ke topik advanced dan scaling.
HTTPS (TLS) mengenkripsi semua data yang bergerak antara browser dan server — termasuk cookie session, password, dan data form. Tanpa HTTPS:
Untuk produksi, HTTPS adalah syarat mutlak, bukan opsional. Sertifikat bisa didapat gratis dari Let's Encrypt atau bawaan dari platform hosting/cloud.
CodeIgniter 4 menyediakan dua mekanisme:
// app/Config/Filters.php
public $aliases = [
'forcehttps' => \CodeIgniter\Filters\ForceHTTPS::class,
];
public $globals = [
'before' => [
'csrf',
'honeypot',
'forcehttps',
],
];public bool $forceGlobalSecureRequests = true;Kedua pendekatan mengarahkan request HTTP ke HTTPS. Kombinasi terbaik: set forceGlobalSecureRequests = true di .env produksi (bukan di config agar development tetap bebas):
app.forceGlobalSecureRequests = true
app.baseURL = 'https://devvnull.vercel.app/'Warning
Jangan pasang forceGlobalSecureRequests di development — development server berjalan di http://localhost tanpa sertifikat, dan setting ini akan membuat redirect loop yang membingungkan. Itulah kenapa nilai ini di .env, bukan di config class.
HSTS memberitahu browser: "jangan pernah akses domain ini via HTTP". Browser yang mendapat header ini langsung memaksa HTTPS bahkan sebelum request:
$response->setHeader(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains'
);max-age=31536000 = satu tahun, includeSubDomains = berlaku juga untuk subdomain. Header ini hanya boleh dikirim melalui HTTPS.
Cookie harus di-flags agar tidak bocor:
public bool $secure = true; // hanya dikirim via HTTPS
public bool $httponly = true; // tidak bisa dibaca JavaScript (anti XSS)
public string $samesite = 'Lax'; // proteksi CSRF level cookie| Flag | Fungsi |
|---|---|
$secure | Cookie hanya dikirim lewat HTTPS |
$httponly | JavaScript tidak bisa baca — meredam XSS |
$samesite | Lax/Strict mencegah pengiriman cookie lintas-situs |
Session cookie secara default httponly dan dikelola CodeIgniter — pastikan secure diaktifkan di produksi dan samesite tidak None tanpa alasan kuat.
Tip
Jika kalian memakai CDN atau reverse proxy (Cloudflare, VPS + proxy), TLS bisa di-terminate di proxy dan koneksi ke aplikasi tetap HTTP internal. Dalam kasus ini set app.forceGlobalSecureRequests = true dan pastikan header X-Forwarded-Proto dipahami framework agar redirect HTTPS tidak loop.
CodeIgniter menyertakan .htaccess di public/ yang menangani URL bersih (tanpa index.php). Untuk memaksa HTTPS, tambahkan aturan:
RewriteEngine On
# Force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Hapus index.php dari URL
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
# Blokir akses file dot (.env, .git)
RewriteRule ^\.|\.env$ - [F,L]Aturan RewriteRule ^\.|\.env$ - [F,L] mengembalikan 403 untuk file tersembunyi — pertahanan tambahan jika ada yang salah konfigurasi document root.
Nginx lebih umum di VPS modern dan performa tinggi. Contoh site block lengkap:
server {
listen 80;
server_name devvnull.vercel.app;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name devvnull.vercel.app;
root /var/www/ci4/public;
index index.php;
ssl_certificate /etc/letsencrypt/live/devvnull.vercel.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/devvnull.vercel.app/privkey.pem;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# Blokir akses file dot
location ~ /\. {
deny all;
}
}Poin penting:
root menunjuk ke public/ — kode aplikasi tidak terekspos.try_files ... /index.php?$args = URL bersih tanpa index.php.location ~ /\. { deny all; } memblokir akses .env, .git, dan file dot lain.Warning
Kesalahan paling umum: meletakkan root di folder project (bukan public/). Akibatnya .env, app/, dan vendor/ bisa diakses browser. Document root selalu ke public/, dan blokir file dot sebagai lapisan kedua.
forceGlobalSecureRequests = true hanya di .env produksi.secure, httponly, samesite.public/..env.forcehttps filter atau forceGlobalSecureRequests..env di .htaccess.root ke public/, try_files, deny file dot.Inti yang harus dibawa pulang:
secure/httponly/samesite melindungi sesi dari sniffing dan XSS.root web server ke public/; blokir akses file dot.forceGlobalSecureRequests hanya untuk produksi.Di episode 21 selanjutnya kita akan masuk fase advanced: advanced query & transaksi — Query Builder lanjutan dengan join, subquery, aggregate, serta transaksi database dan model callbacks untuk laporan kompleks. Data kalian akan diolah jauh lebih dalam!