Ketika aplikasi PHP kamu mulai memiliki pengguna aktif, transaksi, dan login sistem, ancaman keamanan menjadi semakin serius. Banyak serangan web tidak hanya datang dari “luar” tapi bisa muncul dari input pengguna yang tidak aman, sesi yang dicuri, atau form tanpa proteksi. Setelah memahami validasi form dan pencegahan SQL Injection & XSS, kini saatnya kita membahas tiga pilar keamanan lanjutan PHP:
-
CSRF Protection (Cross-Site Request Forgery)
-
Session Hijacking Protection
-
Password Hashing & Verification
1. CSRF (Cross-Site Request Forgery)
Apa itu CSRF?
CSRF adalah serangan di mana penyerang memaksa pengguna yang sedang login untuk melakukan tindakan tanpa disadari, seperti:
-
Menghapus data
-
Mengganti email
-
Mengirim transaksi
Contohnya, jika aplikasi tidak memiliki proteksi CSRF, penyerang bisa membuat halaman tersembunyi seperti:
<img src="https://example.com/delete.php?id=1">
Jika korban sedang login di example.com, maka data bisa terhapus otomatis tanpa konfirmasi.
Solusi: Gunakan CSRF Token
CSRF Token adalah string acak unik yang disertakan pada setiap form dan diverifikasi di server.
Contoh Implementasi:
Buat token saat sesi dimulai:
<?php
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
?>
Tambahkan token ke form:
<form method="post" action="proses.php"> <input type="hidden" name="token" value="<?= $_SESSION['token']; ?>"> <button type="submit">Hapus Data</button> </form>
Validasi token di proses.php:
<?php
session_start();
if (!isset($_POST['token']) || $_POST['token'] !== $_SESSION['token']) {
die("Permintaan tidak valid!");
}
?>
Keuntungan:
-
Tiap form punya identitas unik.
-
Serangan otomatis dari luar domain tidak akan berhasil.
2. Session Hijacking (Pencurian Sesi)
Apa itu Session Hijacking?
Session hijacking terjadi ketika penyerang mencuri session ID pengguna agar bisa login sebagai orang lain tanpa password.
Biasanya dilakukan lewat:
-
Cookie yang tidak aman
-
URL yang mengandung
?sessionid=... -
Serangan XSS yang mencuri cookie
Solusi 1: Gunakan session_regenerate_id()
Setiap kali pengguna login, ubah session ID lama menjadi baru untuk mencegah reuse.
<?php session_start(); session_regenerate_id(true); // hapus ID lama $_SESSION['user'] = $username; ?>
Solusi 2: Batasi Sesi Berdasarkan IP dan User Agent
Tambahkan pemeriksaan di setiap halaman yang butuh login.
<?php
session_start();
if (!isset($_SESSION['user'])) {
header("Location: login.php");
exit;
}
// Validasi tambahan
if ($_SESSION['ip'] !== $_SERVER['REMOTE_ADDR'] ||
$_SESSION['ua'] !== $_SERVER['HTTP_USER_AGENT']) {
session_destroy();
die("Sesi tidak valid!");
}
?>
Saat login pertama kali:
<?php $_SESSION['ip'] = $_SERVER['REMOTE_ADDR']; $_SESSION['ua'] = $_SERVER['HTTP_USER_AGENT']; ?>
Solusi 3: Gunakan Cookie Aman
Gunakan pengaturan berikut sebelum session_start():
<?php
ini_set('session.cookie_httponly', 1); // Tidak bisa diakses JS
ini_set('session.cookie_secure', 1); // Hanya dikirim lewat HTTPS
ini_set('session.use_strict_mode', 1); // Tidak terima session ID palsu
session_start();
?>
3. Password Hashing & Verification
Kesalahan Umum Developer Pemula
Banyak aplikasi lama masih menyimpan password dalam bentuk plaintext (teks asli). Itu sama saja seperti menulis password di papan pengumuman.
Solusi Modern: Gunakan password_hash() dan password_verify()
Contoh Saat Registrasi
<?php
$password = $_POST['password'];
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->bind_param("ss", $username, $hashedPassword);
$stmt->execute();
?>
Contoh Saat Login
<?php
$stmt = $conn->prepare("SELECT password FROM users WHERE username=?");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($hashedPassword);
$stmt->fetch();
if (password_verify($_POST['password'], $hashedPassword)) {
echo "Login sukses!";
} else {
echo "Password salah!";
}
?>
Kelebihan:
-
password_hash()otomatis menambahkan salt (acak). -
password_verify()mencocokkan secara aman tanpa tahu algoritma. -
Bisa diupgrade algoritmanya tanpa ubah data lama.
Bonus: Batasi Upaya Login Gagal
Untuk mencegah brute force attack, simpan jumlah percobaan login di database atau session.
<?php
if (!isset($_SESSION['login_attempt'])) {
$_SESSION['login_attempt'] = 0;
}
if ($_SESSION['login_attempt'] >= 3) {
die("Terlalu banyak percobaan. Coba lagi nanti.");
}
// Setelah login gagal
$_SESSION['login_attempt']++;
?>
Kesimpulan
| Fitur Keamanan | Tujuan | Solusi |
|---|---|---|
| CSRF | Mencegah permintaan palsu dari luar domain | Token unik per form |
| Session Hijacking | Mencegah pencurian sesi login | session_regenerate_id(), validasi IP & User-Agent |
| Password Hashing | Melindungi password pengguna | password_hash() & password_verify() |
Dengan menggabungkan tiga teknik di atas, aplikasi PHP kamu akan jauh lebih aman, stabil, dan siap online secara profesional.