CodeIgniter 4 menawarkan fondasi yang ringan, tetapi penguatan auth guard, session, dan secret handling perlu diatur secara eksplisit untuk mencegah pencurian sesi dan kebocoran credential. Dalam dua paragraf pertama ini, pembaca mendapatkan gambaran bahwa jawaban atas masalah keamanan adalah memasang mekanisme guard/CSRF yang konsisten, session terenkripsi dengan lifetime terkendali, serta secret yang berada di tempat terbatas.
Artikel ini akan membimbing langkah demi langkah: konfigurasi guard/token, session settings yang tepat, pengelolaan secret dengan siklus rotasi, validasi upload/penyekatan abuse, serta checklist audit untuk memastikan semua aspek sudah dipantau.
1. Auth Guard dan Strategi Token untuk API dan Form
Untuk mempertahankan prinsip least privilege, pisahkan guard untuk interaksi pengguna berbasis sesi dan API berbasis token. Gunakan filter khusus di App\Filters agar semua request dicek sebelum mencapai controller.
Nonaktifkan CSRF default? Jangan. Aktifkan CSRFProtection di Config\App.php dan pastikan token diregenerasi setiap request untuk menghindari replay.
$config = config('App');
$config->CSRFProtection = true;
$config->CSRFRegenerate = true;
$config->CSRFTokenName = 'csrf_token';
$config->CSRFHeaderName = 'X-CSRF-TOKEN';
Untuk API, buat filter yang mengurai header Authorization dan memvalidasi JWT atau Personal Access Token yang disimpan secara hashed di basis data.
namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\Config\Services;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class ApiTokenFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
$header = $request->getHeaderLine('Authorization');
if (! $header || ! str_starts_with($header, 'Bearer ')) {
return Services::response()->setStatusCode(401)->setBody('Token tidak ditemukan.');
}
$token = substr($header, 7);
try {
$payload = JWT::decode($token, new Key(env('JWT_SECRET'), 'HS256'));
} catch (\Throwable $e) {
return Services::response()->setStatusCode(401)->setBody('Token tidak valid.');
}
$request->user = $payload->sub ?? null;
return null;
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
}
Strategi token token-facing termasuk:
- Mengeluarkan JWT dengan
iat,exp, danjtiuntuk mendeteksi token reuse. - Menyimpan hashed Personal Access Token dalam tabel tersendiri dan mencocokkan
hash_equals(). - Menerapkan rotasi CSRF dengan header melalui filter agar form lama tidak bisa dipakai ulang.
2. Mengunci Session: driver, enkripsi, lifetime, dan perlindungan hijacking
Session handler default file cukup for development; produksi sebaiknya gunakan driver database atau Redis agar sesi tidak bocor di filesystem bersama. Contoh konfigurasi di Config\Session.php:
public $driver = 'CodeIgniter\Session\Handlers\DatabaseHandler';
public $cookieName = 'ci_session';
public $expiration = 3600;
public $savePath = 'ci_sessions';
public $matchIP = true;
public $matchUserAgent = true;
public $timeToUpdate = 300;
public $regenerateDestroy = true;
Pastikan tabel ci_sessions tersedia dengan kolom id, ip_address, timestamp, dan data. Set $matchIP untuk membatasi sesi hanya ke IP awal (perhatikan load balancer/proxy). Aktifkan enkripsi session melalui Config\Encryption dan simpan encryptionKey di .env.
Untuk melindungi dari sesi hijacking, panggil session()->regenerate(true) setelah login dan logout untuk mengosongkan session lama. Gunakan middleware/filter untuk mengecek header X-Requested-With dan `User-Agent` secara sederhana agar tidak ada request langsung dari bot sedangkan sesi masih aktif.
3. Secret Handling: .env, akses terbatas, rotasi
Simpan semua rahasia (secret JWT, database, API keys) di .env. Jangan commit file tersebut, buat .env.example sebagai referensi. Contoh entri:
JWT_SECRET=asecretpanjang123
ENCRYPTION_KEY=panjangnya32karakterataulebih
CI_SESSION_SECRET=lebihpanjanglagidencrypt
Praktiknya:
- Berikan akses file
.envhanya ke tim deployment. Server production biasanya tidak memiliki akses git. - Buat prosedur rotasi: ubah secret di
.env, restart PHP-FPM, dan pastikan semua deployment pipeline mengetahui perubahan agar tidak terjadi downtime. - Untuk secret yang digunakan oleh worker/background job, pastikan environment variabel diatur ulang sebelum job berjalan.
Jika menggunakan pipeline CI/CD, baca secret dari vault (HashiCorp Vault, AWS Secrets Manager) dan tulis ke file .env saat deployment, bukan menyimpannya di repo.
4. Validasi Input, Upload, dan Rate Limiting
Validasi adalah garis pertahanan pertama. Gunakan rules bawaan dan custom untuk mengecek string length, tipe file, serta MIME. Untuk upload:
$file = $this->request->getFile('lampiran');
if (! $file->isValid() || $file->hasMoved()) {
throw new \RuntimeException('File tidak valid.');
}
if (! $file->isValid() || ! in_array($file->getMimeType(), ['image/jpeg', 'image/png'])) {
return redirect()->back()->with('error', 'Format file tidak diizinkan.');
}
$file->store('uploads', $file->getRandomName());
Tambahkan rule ukuran maksimal (max_size) dan gunakan library seperti Fileinfo untuk validasi MIME, bukan hanya ekstensi.
Untuk rate limiting sederhana, manfaatkan cache memori:
$cache = cache();
$key = 'rate:' . $this->request->getIPAddress();
$count = $cache->get($key) ?? 0;
if ($count > 20) {
return $this->response->setStatusCode(429)->setBody('Terlalu banyak permintaan.');
}
$cache->save($key, $count + 1, 60);
Jika Anda menggunakan Redis atau APCu, tingkatkan granularitas berdasarkan endpoint. Gabungkan rate limit dengan logging untuk tracing abuse.
5. Checklist Audit Keamanan
- Auth: Filter guard dipasang di route, CSRF dan token API divalidasi, dan token tidak disimpan dalam localStorage tanpa enkripsi.
- Session: Driver produksi (database/Redis) aktif,
matchIPdiaktifkan, dan session regenerasi dipanggil setelah login. - Secret: Rahasia hanya di
.env, tidak dipush ke repo, dan rotasi rutin terdokumentasi. - Input: Validasi rule lengkap (tipe, ukuran, format), file upload disimpan di folder non-public.
- Rate limit: Cache hit counter per IP ditetapkan, 429 dikembalikan untuk abuse.
- Logging: Gagal autentikasi atau validasi disimpan untuk audit tanpa mencetak secret.
Gunakan audit checklist ini setiap kali ada perubahan critical (misalnya penambahan endpoint API) sehingga tidak melewatkan konfigurasi keamanan esensial.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!