CodeIgniter 4: rotasi session ID dan cookie aman untuk login adalah fondasi untuk mencegah session fixation, memperkecil risiko pencurian sesi, dan menjaga alur autentikasi tetap konsisten. Implementasi yang benar bukan hanya soal memanggil fungsi login, tetapi juga memastikan session ID diganti pada momen yang tepat, cookie diberi atribut keamanan yang sesuai, dan sesi diakhiri dengan bersih saat logout.
Dalam praktiknya, masalah umum bukan terletak pada form login, melainkan pada detail setelah autentikasi berhasil: session lama tetap dipakai, cookie tidak diberi flag HttpOnly atau Secure, timeout tidak dibedakan antara idle dan absolute, atau fitur remember-me dibuat terlalu longgar. Panduan ini membahas implementasi yang realistis di CodeIgniter 4, termasuk contoh konfigurasi App.php, potongan controller/filter, dan checklist pengujian manual.
Mengapa session harus dirotasi setelah login?
Tujuan utama rotasi session ID adalah mencegah session fixation. Serangan ini terjadi ketika penyerang berhasil membuat korban menggunakan session ID yang sudah diketahui sebelumnya. Jika aplikasi mempertahankan ID yang sama setelah login, penyerang dapat memakai sesi tersebut untuk mengambil alih akses.
Karena itu, setelah autentikasi berhasil, aplikasi perlu:
- mengganti session ID lama dengan yang baru,
- memindahkan data yang memang masih relevan,
- menghapus atau menimpa data sesi sementara yang tidak lagi dibutuhkan.
Prinsip yang sama berlaku saat terjadi perubahan privilege, misalnya:
- user biasa berubah menjadi admin setelah verifikasi tambahan,
- user melewati langkah MFA,
- impersonation/admin switch user,
- proses re-auth untuk tindakan sensitif.
Intinya, setiap perubahan tingkat kepercayaan identitas sebaiknya diikuti rotasi session ID.
Konfigurasi dasar cookie aman di CodeIgniter 4
Di CodeIgniter 4, perilaku cookie dan session dipengaruhi konfigurasi aplikasi. Nama properti dapat sedikit berbeda tergantung versi, jadi gunakan dokumentasi versi proyek Anda sebagai acuan final. Namun, prinsip keamanannya tetap sama: aktifkan HttpOnly, gunakan Secure di koneksi HTTPS, dan pilih SameSite yang sesuai.
Contoh konfigurasi App.php
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
public string $cookiePrefix = '';
public string $cookieDomain = '';
public string $cookiePath = '/';
public bool $cookieSecure = true;
public bool $cookieHTTPOnly = true;
public string $cookieSameSite = 'Lax';
// Pastikan baseURL menggunakan https pada deployment HTTPS.
public string $baseURL = 'https://example.com/';
}
Makna atribut di atas:
- HttpOnly: mencegah akses cookie dari JavaScript di browser. Ini tidak menghentikan semua serangan XSS, tetapi mengurangi risiko pencurian cookie melalui script.
- Secure: cookie hanya dikirim lewat HTTPS. Ini wajib untuk lingkungan produksi yang menggunakan TLS.
- SameSite=Lax: pilihan aman untuk banyak aplikasi web biasa karena masih kompatibel dengan navigasi normal. Jika aplikasi benar-benar membutuhkan pengiriman cookie lintas situs, evaluasi
SameSite=Nonedengan konsekuensi keamanan dan syaratSecure.
Catatan: Untuk alur login aplikasi web tradisional,
SameSite=Laxbiasanya cukup baik. NilaiStrictlebih ketat tetapi bisa memengaruhi sebagian alur redirect atau integrasi tertentu. GunakanNonehanya jika memang diperlukan.
Rotasi session ID setelah login dan perubahan privilege
Contoh controller login
Setelah kredensial tervalidasi, lakukan regenerasi sesi sebelum atau saat menetapkan identitas user pada sesi baru. Tujuannya adalah memastikan konteks autentikasi tidak menempel pada session ID yang lama.
<?php
namespace App\Controllers;
use App\Models\UserModel;
use CodeIgniter\HTTP\RedirectResponse;
class AuthController extends BaseController
{
public function login(): RedirectResponse|string
{
if ($this->request->getMethod() === 'get') {
return view('auth/login');
}
$email = trim((string) $this->request->getPost('email'));
$password = (string) $this->request->getPost('password');
$users = new UserModel();
$user = $users->where('email', $email)->first();
if (! $user || ! password_verify($password, $user['password_hash'])) {
return redirect()->back()->withInput()->with('error', 'Email atau password salah.');
}
$session = session();
// Rotasi ID untuk mencegah session fixation.
$session->regenerate(true);
$session->set([
'user_id' => $user['id'],
'user_email' => $user['email'],
'role' => $user['role'],
'is_authenticated' => true,
'login_time' => time(),
'last_activity' => time(),
]);
return redirect()->to('/dashboard');
}
}
Poin pentingnya bukan sekadar memanggil regenerate(), tetapi memastikan:
- rotasi terjadi saat autentikasi berhasil,
- data autentikasi disimpan pada sesi hasil rotasi,
- session lama tidak dibiarkan tetap valid lebih lama dari yang perlu.
Rotasi saat privilege berubah
Jika user baru saja lolos MFA atau diberi akses admin untuk area sensitif, lakukan rotasi ulang. Ini mengurangi risiko bahwa sesi dengan tingkat privilege lebih rendah berubah menjadi lebih tinggi tanpa pergantian identitas sesi.
<?php
public function completeMfa()
{
$session = session();
// Setelah MFA sukses, privilege sesi meningkat.
$session->regenerate(true);
$session->set([
'mfa_passed' => true,
'elevated_until' => time() + 900,
'last_activity' => time(),
]);
return redirect()->to('/settings/security');
}
Trade-off: terlalu sering merotasi sesi dapat menambah kompleksitas debugging, terutama jika aplikasi membuka banyak tab atau ada request paralel. Namun untuk login dan perubahan privilege, manfaat keamanannya jelas lebih besar.
Timeout idle vs absolute session timeout
Banyak aplikasi hanya mengandalkan masa hidup sesi standar. Itu belum tentu cukup. Praktik yang lebih aman adalah membedakan dua jenis timeout:
- Idle timeout: user dianggap tidak aktif setelah tidak ada aktivitas selama periode tertentu.
- Absolute timeout: sesi harus berakhir setelah durasi maksimum, walaupun user masih aktif.
Kombinasi ini mencegah sesi bertahan terlalu lama, sekaligus tetap masuk akal untuk UX.
Contoh filter untuk mengelola lifecycle session
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class SessionLifecycleFilter implements FilterInterface
{
private int $idleTimeout = 1800; // 30 menit
private int $absoluteTimeout = 28800; // 8 jam
public function before(RequestInterface $request, $arguments = null)
{
$session = session();
if (! $session->get('is_authenticated')) {
return;
}
$now = time();
$loginTime = (int) $session->get('login_time');
$lastActivity = (int) $session->get('last_activity');
if ($loginTime > 0 && ($now - $loginTime) > $this->absoluteTimeout) {
$session->destroy();
return redirect()->to('/login')->with('error', 'Sesi berakhir. Silakan login kembali.');
}
if ($lastActivity > 0 && ($now - $lastActivity) > $this->idleTimeout) {
$session->destroy();
return redirect()->to('/login')->with('error', 'Sesi kedaluwarsa karena tidak aktif.');
}
$session->set('last_activity', $now);
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
}
Daftarkan filter ini pada rute atau grup yang membutuhkan autentikasi. Dengan begitu, setiap request terlindungi oleh aturan lifecycle sesi yang konsisten.
Trade-off:
- Idle timeout terlalu pendek akan mengganggu UX, terutama untuk form panjang atau dashboard yang dibuka lama.
- Absolute timeout terlalu panjang memperbesar jendela risiko jika perangkat ditinggalkan dalam keadaan login.
Pilihan durasi harus mengikuti tingkat sensitivitas aplikasi. Backoffice finansial dan panel admin biasanya butuh batas lebih ketat dibanding portal konten biasa.
Logout yang benar: invalidasi session dan hapus jejak cookie
Logout yang aman tidak cukup hanya menghapus flag is_authenticated. Anda perlu mengakhiri seluruh sesi agar data autentikasi, privilege sementara, dan token terkait tidak tertinggal.
Contoh controller logout
<?php
public function logout()
{
$session = session();
// Jika ada token remember-me di database, cabut di sini.
// contoh: $this->rememberMeService->revokeForCurrentDevice(...);
$session->destroy();
return redirect()->to('/login')->with('message', 'Anda telah logout.');
}
Jika aplikasi memakai cookie tambahan di luar session utama, hapus juga cookie tersebut saat logout. Pastikan atribut domain/path yang dipakai saat menghapus sama dengan saat membuat cookie; jika tidak, browser bisa mempertahankan cookie lama.
Kesalahan umum saat logout:
- hanya menghapus sebagian key session, bukan seluruh sesi,
- lupa mencabut token remember-me,
- redirect terjadi tetapi cookie sesi masih valid,
- menghapus cookie dengan path/domain yang berbeda sehingga tidak benar-benar hilang.
Mitigasi remember-me yang berisiko
Fitur remember-me sering menjadi sumber masalah karena sengaja membuat autentikasi bertahan lebih lama. Jika diimplementasikan secara ceroboh, ia dapat menjadi jalur bypass terhadap timeout sesi normal.
Prinsip yang lebih aman:
- jangan simpan password atau hash password langsung di cookie,
- gunakan token acak bernilai tinggi entropinya,
- simpan token dalam bentuk yang dapat divalidasi server-side, idealnya dengan pencatatan perangkat atau rotasi token,
- bedakan masa berlaku remember-me dari sesi login aktif,
- cabut token saat logout, ganti password, atau aktivitas mencurigakan,
- jangan otomatis menaikkan privilege sensitif hanya dari cookie remember-me.
Pola yang disarankan
Gunakan cookie remember-me hanya untuk memulihkan identitas dasar, lalu buat sesi baru yang segar di server dan tetap lakukan rotasi session ID. Untuk tindakan sensitif, minta re-auth atau MFA walaupun user dipulihkan dari remember-me.
Praktik aman: anggap remember-me sebagai mekanisme kenyamanan, bukan sebagai bukti autentikasi penuh untuk operasi sensitif seperti ubah email, ubah password, atau akses panel admin kritis.
Reverse proxy, HTTPS terminator, dan dampaknya pada flag Secure
Pada banyak deployment, aplikasi CodeIgniter 4 berada di belakang reverse proxy, load balancer, atau HTTPS terminator. Koneksi dari browser ke proxy memakai HTTPS, tetapi koneksi dari proxy ke aplikasi bisa saja HTTP internal. Di sinilah konfigurasi sering keliru.
Masalah utamanya: aplikasi mungkin mengira request datang lewat HTTP biasa, sehingga:
- URL redirect menjadi
http://alih-alihhttps://, - cookie dengan flag Secure tidak diterapkan sebagaimana diharapkan,
- deteksi skema request tidak konsisten.
Trade-off dan hal yang perlu diperhatikan
- Jika
Secure=truepada produksi HTTPS, cookie sesi tidak akan dikirim lewat HTTP biasa. Ini benar dari sisi keamanan, tetapi bisa membuat login tampak gagal jika lingkungan staging/lokal belum HTTPS. - Jika aplikasi berada di balik proxy, pastikan server/proxy meneruskan header yang relevan dan aplikasi/server web dikonfigurasi untuk mempercayai proxy yang benar. Tanpa itu, deteksi HTTPS bisa salah.
- Jangan menonaktifkan Secure hanya untuk “memperbaiki” gejala di produksi. Lebih baik benahi konfigurasi proxy dan base URL.
Secara operasional, verifikasi hal berikut:
baseURLproduksi menggunakanhttps://,- proxy meneruskan informasi skema asli request,
- server web dan framework memahami bahwa request eksternal datang melalui HTTPS,
- cookie sesi dan redirect setelah login diuji dari browser nyata, bukan asumsi dari konfigurasi saja.
Contoh filter autentikasi sederhana
Selain lifecycle sesi, banyak aplikasi membutuhkan filter yang memastikan user sudah login sebelum mengakses route tertentu.
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class AuthFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
if (! session()->get('is_authenticated')) {
return redirect()->to('/login')->with('error', 'Silakan login terlebih dahulu.');
}
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
}
}
Gabungkan AuthFilter dengan filter lifecycle session agar akses route terlindungi dan timeout diterapkan secara konsisten.
Kesalahan umum yang sering muncul
- Tidak merotasi session ID setelah login. Ini inti dari risiko session fixation.
- Menyimpan terlalu banyak data sensitif di session. Simpan seperlunya; lebih banyak data berarti lebih banyak dampak jika sesi bocor.
- Mengaktifkan remember-me tanpa invalidasi server-side. Cookie jangka panjang tanpa kontrol pencabutan adalah titik lemah.
- Secure cookie gagal di lingkungan proxy. Biasanya gejalanya login berulang, redirect aneh, atau sesi tidak bertahan.
- Tidak membedakan idle dan absolute timeout. Hasilnya bisa terlalu longgar atau terlalu mengganggu pengguna.
Checklist pengujian manual
Setelah implementasi, lakukan pengujian manual dari browser, bukan hanya unit test. Gunakan DevTools untuk memeriksa cookie, network, dan redirect.
1. Verifikasi rotasi session ID
- Buka halaman login dan catat cookie sesi sebelum autentikasi.
- Login dengan akun valid.
- Pastikan nilai cookie sesi berubah setelah login berhasil.
- Ulangi saat MFA sukses atau privilege meningkat, dan pastikan ID berubah lagi.
2. Verifikasi atribut cookie
- Lihat cookie sesi di browser DevTools.
- Pastikan HttpOnly aktif.
- Pada deployment HTTPS, pastikan Secure aktif.
- Pastikan SameSite sesuai desain aplikasi, biasanya
Lax.
3. Uji redirect dan skema URL
- Setelah login, pastikan redirect menuju URL
https://pada produksi. - Jika memakai reverse proxy, pastikan tidak ada redirect bolak-balik antara HTTP dan HTTPS.
- Periksa apakah sesi tetap bertahan setelah redirect.
4. Uji idle timeout
- Login, lalu diamkan browser melebihi batas idle timeout.
- Refresh halaman atau akses route terlindungi.
- Pastikan user diminta login lagi dan sesi lama tidak dipakai ulang.
5. Uji absolute timeout
- Login dan tetap aktif menggunakan aplikasi.
- Setelah melewati batas absolute timeout, akses route terlindungi.
- Pastikan sesi tetap berakhir walaupun user sebelumnya aktif.
6. Uji logout
- Login lalu logout.
- Pastikan cookie sesi hilang atau tidak lagi valid.
- Tekan tombol back browser dan coba akses ulang halaman privat.
- Pastikan server menolak akses dan meminta login kembali.
7. Uji remember-me dengan skenario gagal
- Aktifkan remember-me lalu logout, pastikan token dicabut.
- Ubah password akun, pastikan remember-me lama tidak lagi memulihkan sesi.
- Jika ada daftar perangkat, cabut satu perangkat dan pastikan token terkait tidak valid.
Penutup
Untuk memperkuat login di CodeIgniter 4, fokus utamanya adalah: rotasi session ID setelah login dan perubahan privilege, cookie sesi yang aman, timeout yang jelas, logout yang benar, dan remember-me yang dibatasi secara ketat. Bagian-bagian ini saling melengkapi. Cookie aman tanpa rotasi sesi masih menyisakan risiko; rotasi sesi tanpa timeout yang baik juga belum cukup.
Jika aplikasi Anda berada di balik reverse proxy atau HTTPS terminator, jangan hanya melihat kode aplikasi. Pastikan juga konfigurasi infrastruktur mendukung pengiriman cookie Secure dan deteksi HTTPS yang benar. Setelah itu, validasi semuanya dengan pengujian manual end-to-end agar keamanan meningkat tanpa memutus pengalaman pengguna.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!