Session menyimpan status login dan data pengunjung di server, sehingga keamanannya menentukan keamanan seluruh aplikasi. Sasaran serangan pada bagian ini adalah session ID, yaitu pengenal yang dibawa cookie dan menjadi satu-satunya penghubung browser dengan data session di server. Topik ini membahas session fixation, regenerasi ID pada titik-titik penting, penyetelan cookie session, dan cara memutus session dengan benar.
Session ID sebagai kredensial#
PHP mengidentifikasi pengunjung melalui session ID yang dikirim browser pada setiap permintaan, sedangkan datanya tersimpan di server dan diisi kembali oleh session_start. Siapa pun yang membawa session ID tertentu dianggap pemilik datanya, sehingga session ID bekerja seperti kredensial. Berbeda dengan kata sandi, session ID berpindah pada setiap permintaan melalui header cookie dan dapat bocor melalui celah lain, misalnya skrip sisipan dari serangan XSS yang membacanya.
Dua pola serangan utama berkaitan erat. Session hijacking adalah pencurian session ID milik pengguna yang sudah login, lalu ID itu dipakai penyerang untuk masuk dengan identitas korban. Session fixation bekerja sebaliknya, yaitu menanamkan session ID pilihan penyerang ke browser korban sebelum korban login, misalnya melalui tautan yang membawa parameter ID. Setelah korban login dengan ID tersebut, penyerang yang mengetahuinya ikut masuk tanpa perlu kata sandi.
Kedua pola itu ditangani dengan kombinasi regenerasi ID, penyetelan cookie yang ketat, dan pembersihan session yang benar, sebagaimana dibahas pada bagian-bagian berikut.
Mencegah session fixation dengan regenerasi ID#
Fungsi session_regenerate_id(true) meminta PHP membuat session ID baru dan menghapus penyimpanan sesi lama, sehingga ID yang sudah diketahui pihak lain kehilangan nilai. Pemanggilannya wajib dilakukan pada setiap perubahan hak akses, terutama segera setelah proses login berhasil dan setelah penggantian kata sandi.
<?php
session_start();
$idLama = session_id();
session_regenerate_id(true);
$idBaru = session_id();
var_dump($idLama !== $idBaru);
session_write_close();bool(true)Keluaran menegaskan bahwa session ID sebelum dan sesudah panggilan berbeda, dan argumen true menghapus penyimpanan sesi lama sehingga ID lama tidak merujuk data apa pun. Pada konteks web, cookie dengan ID baru dikirim ke browser, sehingga ID yang ditanam penyerang sebelum login menjadi tidak berguna. Regenerasi tidak mengosongkan $_SESSION, sehingga data login yang baru ditulis tetap tersimpan di bawah ID yang baru.
Frekuensi regenerasinya perlu seimbang. Pemanggilan sekali sesudah login dan pada setiap kenaikan hak akses sudah menutup pola fixation, sedangkan regenerasi pada setiap permintaan menambah keamanan tetapi dapat membebani penyimpanan sesi yang penuh berkas lama.
Menyetel cookie session yang aman#
Cookie session disetel melalui session_set_cookie_params sebelum session_start, dan setiap opsi menutup satu celah serangan.
| Opsi | Nilai yang disarankan | Celah yang ditutup |
|---|---|---|
httponly | true | Skrip di browser tidak dapat membaca cookie |
secure | true | Cookie tidak terkirim melalui HTTP biasa |
samesite | Strict atau Lax | Cookie tidak terkirim dari konteks lintas situs |
lifetime | 0 | Cookie berakhir saat browser ditutup |
<?php
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Strict',
]);
$params = session_get_cookie_params();
echo 'lifetime : ' . $params['lifetime'] . PHP_EOL;
echo 'secure : ' . var_export($params['secure'], true) . PHP_EOL;
echo 'httponly : ' . var_export($params['httponly'], true) . PHP_EOL;
echo 'samesite : ' . $params['samesite'] . PHP_EOL;lifetime : 0
secure : true
httponly : true
samesite : StrictKeluaran menegaskan bahwa seluruh opsi terbaca kembali melalui session_get_cookie_params, sehingga pengaturannya dapat diperiksa sebelum sesi dibuka. Nilai secure menuntut HTTPS, sehingga pada pengembangan lokal melalui HTTP biasa cookie tersebut tidak terkirim dan opsi itu diaktifkan pada penerapan produksi. Nilai lifetime nol membuat cookie berakhir bersama sesi browser. Masa berlaku data di sisi server diatur sendiri, misalnya dengan menyimpan waktu aktivitas terakhir di $_SESSION dan menghapus sesi ketika melewati batas yang ditetapkan.
Memutus session dengan benar#
Proses keluar yang benar mengosongkan $_SESSION dan menghapus data di penyimpanan server melalui session_destroy. Keduanya perlu dijalankan karena fungsi tersebut tidak mengosongkan variabel di memori skrip.
<?php
session_start();
$_SESSION['pengguna'] = 'Dewi';
var_dump(session_destroy());
var_dump(isset($_SESSION['pengguna']));
$_SESSION = [];
var_dump(isset($_SESSION['pengguna']));bool(true)
bool(true)
bool(false)Keluaran menunjukkan perilaku yang sering mengejutkan. Setelah session_destroy, nilai $_SESSION['pengguna'] masih terbaca karena fungsi itu menghapus data di penyimpanan server dan bukan isi variabel di memori, sehingga kode setelahnya masih menganggap pengguna login. Pengosongan dengan $_SESSION = [] menyelesaikannya, dan cookie pengenal yang tersisa di browser tidak lagi merujuk data apa pun karena ID-nya sudah tidak valid di server.
Kesalahan umum#
Empat kesalahan berikut paling sering muncul saat mengelola session.
- Session ID tidak diregenerasi sesudah login. ID yang ditanam penyerang tetap sah sehingga session fixation berhasil. Perbaikannya adalah
session_regenerate_id(true)segera setelah status login berubah. - Proses keluar hanya memanggil
session_destroy. Isi$_SESSIONmasih terbaca dalam skrip yang sama sehingga kode setelahnya menganggap pengguna masih login. Perbaikannya adalah mengosongkan$_SESSIONterlebih dahulu, lalu memanggilsession_destroy. - Cookie session dibiarkan tanpa
httponly. Skrip sisipan dari celah XSS dapat membaca cookie dan mengirimkannya ke server penyerang. Perbaikannya adalahhttponlybernilaitruepadasession_set_cookie_params. - Masa berlaku session dibiarkan tanpa batas. ID yang bocor tetap hidup berhari-hari sehingga jendela penyalahgunaan memanjang. Perbaikannya adalah mencatat waktu aktivitas di
$_SESSIONdan menghapus sesi yang melewati batas.
Ringkasan#
- Session ID berperan sebagai kredensial, sehingga pencurian maupun penetapan ID sama berbahayanya dengan kebocoran kata sandi.
session_regenerate_id(true)mengganti ID dan menghapus penyimpanan sesi lama, dan wajib dijalankan sesudah login serta perubahan hak akses.session_set_cookie_paramsmenyetelhttponly,secure, dansamesitesebelumsession_startdipanggil.- Proses keluar yang benar mengosongkan
$_SESSIONlalu memanggilsession_destroy, karena pemanggilan tunggal tidak mengosongkan variabel di memori.
Referensi#
- session_regenerate_id — PHP Manual — Dokumentasi penggantian session ID beserta penghapusan sesi lamanya.
- session_set_cookie_params — PHP Manual
— Dokumentasi opsi cookie session seperti
httponlydansamesite. - session_destroy — PHP Manual — Dokumentasi penghapusan data session di penyimpanan server.
- Session Security — PHP Manual — Catatan keamanan session, termasuk fixation dan penyimpanan session ID.