Cara menggunakan php secure session

Membuat Secure Login dengan Captcha dan Session Expire

Info Post

Unknown

06.40

Keamanan sangat penting nilainya guna mengamankan data pada aplikasi web (web application) agar tidak terjadi kecolongan akses dan data penting.
Pada contoh source code yang saya upload kali ini, saya sertakan script captcha sebagai verifikasi dan Session Expire sebagai pembatas akses jika aplikasi tidak digunakan dalam jangka waktu 5 menit (timer dapat disesuaikan dengan keinginan masing-masing).
Disini saya hanya mencontohkan dalam bentuk sederhana, masih banyak kekurangan dalam contoh source code ini yang mungkin dapat anda kembangkan sendiri nanti. Contoh pengembangan yang dapat anda lakukan adalah pembatasan masa login jika terjadi beberapa kali kesalahan saat input data login.

Cara menggunakan source  :
- extract file Secure-login.zip nya lalu copy ke direktori localhost anda
- export database.sql nya melalui phpmyadmin
- buka browser lalu masuk ke direktori secure login di localhost. Misal : http://localhost/login
- login dengan username : admin ; password : admin ; dan isi captcha sesuai karakter yang ada di gambar
Selamat Mencoba

Cara menggunakan php secure session


Download Sourcecode

di 06.40

Cara menggunakan php secure session

Kirimkan Ini lewat EmailBlogThis!Berbagi ke TwitterBerbagi ke FacebookBagikan ke Pinterest

Label: Keamanan, php

Share:

  • Facebook
  • Twitter
  • Google+
  • StumbleUpon
  • Digg
  • Delicious
  • LinkedIn
  • Reddit
  • Technorati

Log In merupakan fitur utama yang paling penting dibuat di sebuah project website. Pada umumnya sistem Log In memanfaatkan cookie dan session, dan hanya menggunakan validasi yang sangat sederhana. Sayangnya seringkali kita lupa kalau sistem Log In itu adalah pintu utama yang kalau terlalu sederhana akan sangat mudah dijebol.. Halaman Log In yang kita buat setidaknya harus mampu menangani serangan-serangan umum seperti berikut ini : 

  • Brute Force Attack : serangan paling primitif (hehe) dimana hacker berusaha menebak segala kemungkinan username dan password secara terus menerus sampai ketemu.
  • SQL Injection : serangan dimana hacker menginputkan injeksi skrip SQL di inputan, dengan harapan skrip tersebut dapat terinjeksi dan berjalan di server untuk mengambil / merusak data tertentu.
  • Session Hijacking : teknik pencurian session di perangkat tertentu. Apabila di script pengecekan log in kita hanya menggunakan fungsi isset() atau sejenisnya, hacker yang mencuri session di perangkat yang sudah log in pun jadi memiliki hak akses yang sama.

Sistem log in yang hanya memanfaatkan session umumnya rentan dengan serangan brute force dan session hijacking. Karena itu di tutorial kali ini kita akan mencoba membuat halaman login dan validasi yang setidaknya mampu mengatasi serangan-serangan tersebut. 

 

Step 1 : Pembuatan Database dan Struktur Tabel

Pertama-tama kita buat databasenya dulu, untuk cepatnya bisa langsung jalankan SQL ini di database yang sudah kita buat..

CREATE TABLE tb_admin
(
	user VARCHAR(50) PRIMARY KEY,
   	pass VARCHAR(255),
    name VARCHAR(50),
    email VARCHAR(100),
    priviledge INT(1)
);

CREATE TABLE tb_admin_log(
	id INT PRIMARY KEY AUTO_INCREMENT,
    tgl DATETIME,
    expired DATETIME,
    token VARCHAR(40),
    username VARCHAR(50),
    ip VARCHAR(20),
    useragent VARCHAR(150),
    stat INT(1)
);

INSERT INTO tb_admin VALUES
('admin','$2y$10$ggxmazeAZOoioEnq4mLXSeLvn404IewZ29AoF7vzZwYuTRqu6AUPK', 'Administrator','admin@localhost',1);

Ada 2 tabel yang perlu kita buat, yaitu tabel tb_admin, fungsinya seperti biasa untuk menampung data admin yang memiliki akses. Di contoh passwordnya menggunakan metode password_hash di PHP, makanya formatnya $2y$10.......... Tabel tb_admin_log akan digunakan untuk merekam segala aktivitas login berhasil maupun login gagal. Tabel tb_admin_log inilah yang akan membantu kita melakukan pengecekan terhadap serangan brute force dan session hijacking.

 

Step 2 : Koneksi dan File Library

Di contoh tutorial ini saya akan menggunakan Native PHP Data Object (PDO). Kalau konsepnya sudah dipahami, nanti bisa diterjemahkan ke framework apa saja kok..

Di folder project kita, buat sebuah folder conf untuk menampung file penting kita yaitu conn.php, library.php, dan ClassLogin.php.

<?php
//conf/conn.php
session_start();

$user = "root";
$pass = "";
$db = "adv_login";
$host = "localhost";

$db = new PDO('mysql:host=localhost;dbname='.$db.';charset=utf8',$user,$pass);

require_once("conf/library.php");
require_once("conf/ClassLogin.php");

$login = new Login();
<?php
//conn/library.php
#isinya adalah fungsi standar untuk pengiriman pesan sukses/error
#fungsi-fungsi kit tambahan lainnya juga bisa sekalian dimasukkan disini

function create_alert($type, $pesan, $header=null){
	$_SESSION['adm-type'] = $type;
	$_SESSION['adm-message'] = $pesan;

	if($header!==null){
		header("location:".$header);
		exit();
	}
}

function show_alert(){
	if(isset($_SESSION['adm-type'])){
		$type = ucfirst($_SESSION['adm-type']);
		unset($_SESSION['adm-type']);
		$message = $_SESSION['adm-message'];
		unset($_SESSION['adm-message']);

		return "
		<div class='alert alert-$type'>
			<strong>$type</strong>
			<br>
			$message
		</div>
		";
	}
}

<?php
//conn/ClassLogin.php

Class Login{
	var $db;

	public function __construct(){
		global $db;
		#menghubungkan variabel database $db ke class Login
		$this->db = $db;
	}

	public function cek_login(){
		//method yang akan memvalidasi apakah sedang dalam keadaan log in atau tidak
		return false;
	}


	Public function salah_login_action($username){
		//method yang akan dipanggil apabila user memasukkan username/password yang salah
		return false;
	}


	public function cek_salah_login($limit=5){
		//method untuk menangkal BRUTE FORCE. 
		//Apabila user terdeteksi salah login sebanyak $limit kali, maka user tidak boleh login lagi
		return true;
	}


	public function true_login($username, $expired){
		//method yang akan dipanggil apabila user memasukkan username dan password yang benar
		return true;
	}

	public function logout(){
		//method yang akan dipanggil apabila user logout dari sistem
		return true;
	}

	public function login_redir(){
		//method yang akan selalu dipanggil di seluruh halaman non index dan non login, 
		//untuk mengecek apabila user tidak memiliki akses langsung diredirect ke halaman login
		if(!$this->cek_login())
			header("location:index.php");
	}

}

Class Login sudah diisi method-method yang nantinya akan digunakan. Default valuenya dibiarkan dulu seperti itu saja, sampai nanti kita edit satu per satu. Sekarang kita akan membuat file index.php di direktori utama project kita.

<?php
//index.php
require("conf/conn.php");

$login_status = $login->cek_login();
if($login_status){
	//bawa ke halaman home
	header("location:home.php");
	exit();
}
else{
	//include form log in jika belum log in
	include "login.php";
}
?>

file conf/conn.php harus selalu diinclude di semua halaman nantinya. Karena di satu file tersebutlah kita memanggil library, class login, dan databasenya. Variabel $login sudah dideklarasikan di file conn.php sebelumnya, sehingga bisa langsung digunakan sebagai objek. Sekarang kita akan membuat form loginnya di file login.php. 

<?php
require_once("conf/conn.php");
?>
<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Form Login</title>
</head>
<body>

<form action="login-proses.php" method="post">
	<h1>Admin Log In</h1>
	<?=show_alert();?>
	Username : <input type="text" name="username">
	<br>
	Password : <input type="password" name="password">
	<br>
	<label for="rmb">
		<input type="checkbox" name="remember" value="1" id="rmb">
		Remember Me
	</label>
	<br>
	<button type="submit" name="btn">Log In</button>
</form>

</body>
</html>

Sederhana saja.. Apabila project tersebut diakses, maka tampilannya adalah seperti ini : 

 

Step 3 : Proses Login 

Sekarang kita membuat file login-proses.php untuk validasinya. Algoritma proses loginnya secara umum adalah : 

  • Cek_Salah_Login() apakah sudah melebihi batas? Jika iya, hentikan eksekusi dan tampilkan pesan error.
  • Cek di database, apakah ada username yang sama seperti yang diinputkan di $_POST[username] ?
    • Jika tidak ada, catat kesalahan login, dan tampilkan pesan error
    • Jika ada, cek password apakah valid atau tidak?
      • Jika valid, lakukan proses pembuatan token, lalu redirect ke halaman index
      • Jika tidak valid, catat kesalahan login, dan tampilkan pesan error

Dengan algoritma tersebut, kita dapat merancang login-proses.php menjadi seperti berikut :

<?php
//login-proses.php
include "conf/conn.php";

if(!$login->cek_salah_login()){
	//kalau user salah login melebihi batas yang ditentukan, maka proses langsung berhenti
	create_alert("error","Mohon maaf Anda tidak dapat login lagi karena kesalahan login Anda terlalu banyak. Hubungi Administrator untuk informasi lebih lanjut","index.php");
}

//tombol $_POST['btn'] harus ditekan. kalau tidak ditekan artinya nggak ada proses apapun yang dijalankan
if(isset($_POST['btn'])){
	$username = $_POST['username'];
	$password = $_POST['password'];

	//step 1 : cek apakah username ada di tabel 
	$cek = $db->query("SELECT * FROM tb_admin WHERE user = ".$db->quote($username));

	if($cek->rowCount() > 0){
		//username ada, tangkap password yg ada di database
		$row = $cek->fetch();
		$password_db = $row['pass'];
		#password_verify adalah fungsi PHP 5.5> yang otomatis mengecek kesamaan inputan dengan hash 
		if(password_verify($password, $password_db)){
			//password sudah cocok

			$expired = 0;
			if(isset($_POST['remember'])){
				if($_POST['remember'] = 1){
					$expired = '+1 year'; // 1 tahun
				}
			}
			#kalau remember me dicentang, login akan expired dalam waktu 1 tahun, selain itu ya akan seperti session biasa yang hilang ketika diclose

			$login->true_login($username, $expired); //pencatatan token akan dilakukan disini
			create_alert("success","Log In Berhasil","index.php");
		}
		else{
			//password tidak cocok
			$login->salah_login_action($username); //pencatatan kesalahan login
			create_alert("error","Username atau password tersebut salah","index.php");
		}

	}
	else{
		$login->salah_login_action($username); //pencatatan kesalahan login
		create_alert("error","Username atau password tersebut tidak terdaftar","index.php");
	}

}

Sampai disini apa sudah bisa berjalan? Jelas..

Jelas belum bisa.. Class Loginnya kan masih kosong begitu.. Sekarang kita akan mengisi seluruh method yang sudah disebutkan di login-proses.php tadi sesuai alur logika yang diinginkan. 

 

Step 4 : Penyesuaian Class Login 

Salin method-method dibawah ini, letakkan sesuai di class Login yang sudah ada tadi. Penjelasan singkatnya bisa dilihat di komentar-komentarnya

...
	public function salah_login_action($username){
		//logic : dipanggil saat user salah memasukkan username/password.
		//username, tgl, ip, dan user agent dicatat dengan FLAG=0.

		$tgl = date("Y-m-d H:i:s");
		$ip = $_SERVER['REMOTE_ADDR'];
		$useragent = $_SERVER['HTTP_USER_AGENT'];

		//memasukkan data ke tb_admin_log dengan flag STAT = 0.
		$save = $this->db->prepare("INSERT INTO tb_admin_log VALUES (NULL, ?, '', '', ?, ?, ?, 0)");
		$save->execute(array(
			$tgl, $username, $ip, $useragent
		));
		return true;
	}
...

 

...
	public function cek_salah_login($limit=5){
		#method ini dipanggil sekali di login-proses paling atas. 
		#$limit bisa disesuaikan sesuai kebutuhan kita. 
		//cek apakah di tabel tb_admin_log ada 5 IP yang sama dalam keadaan salah login (STAT = 0)

		$ip = $_SERVER['REMOTE_ADDR'];
		$cek = $this->db->prepare("SELECT * FROM tb_admin_log WHERE stat = 0 AND ip = ?");

		$cek->execute(array($ip));
		if($cek->rowCount() >= $limit)
			return false;
		return true;
	}
...

 

...
	public function true_login($username, $expired){
		#method yang dipanggil ketika username dan password sudah tepat dimasukkan

		$tgl = date("Y-m-d H:i:s");
		if($expired <> 0){
			#kalau remember me dicentang, tanggal expirenya adalah 1 tahun dari sekarang.
			$expireddb = date("Y-m-d H:i:s",strtotime($expired));
		}
		else{
			#kalau remember me tidak dicentang, secara default user dapat login selama 6 jam saja.
			$expireddb = date("Y-m-d H:i:s",strtotime("+6 hours"));
		}

		$ip = $_SERVER['REMOTE_ADDR'];
		$useragent = $_SERVER['HTTP_USER_AGENT'];

		$token = sha1($ip.$expireddb."string_random_apasaja".microtime()); //intinya membuat karakter acak saja
		//$token ini penting,, nantinya akan disimpan sebagai COOKIE

		//apabila ada kesalahan login sebelumnya dengan IP & user agent yang sama sebelumnya harus ditandai dulu 
		//penandaan dilakukan dengan mengubah FLAG dari 0 menjadi 9, sehingga di pengecekan selanjutnya data ini tidak akan dianggap
		$upd = $this->db->query("UPDATE tb_admin_log SET stat = 9 WHERE token = '' AND ip = ".$this->db->quote($ip)." AND useragent = ".$this->db->quote($useragent));


		//memasukkan data lengkap ke tb_admin_log dengan flag STAT = 1.
		$save = $this->db->prepare("INSERT INTO tb_admin_log VALUES (NULL, ?, ?, ?, ?, ?, ?, 1)");
		$save->execute(array(
			$tgl, $expireddb, $token, $username, $ip, $useragent
		));


		//simpan token ke cookie
		$expr = 0;
		if($expired <> 0){
			$expr = intval(strtotime($expired));
		}
		setcookie("adv_token", $token, $expr, "/");
		#kalau remember me tidak dicentang, cookie akan otomatis bertindak sebagai session
		#kalau dicentang, cookie akan terus disimpan

		return true;
	}
...

 

<?php
//conf/conn.php
session_start();

$user = "root";
$pass = "";
$db = "adv_login";
$host = "localhost";

$db = new PDO('mysql:host=localhost;dbname='.$db.';charset=utf8',$user,$pass);

require_once("conf/library.php");
require_once("conf/ClassLogin.php");

$login = new Login();
0

 

Dan terakhir ....

<?php
//conf/conn.php
session_start();

$user = "root";
$pass = "";
$db = "adv_login";
$host = "localhost";

$db = new PDO('mysql:host=localhost;dbname='.$db.';charset=utf8',$user,$pass);

require_once("conf/library.php");
require_once("conf/ClassLogin.php");

$login = new Login();
1

 

Last Step : Pengujian

Untuk menguji, kita akan membuat file tambahan di direktori utama : home.php. Karena di halaman index.php sebelumnya sudah dibuat kondisi cek_login(), jika true akan diarahkan ke home.php.

<?php
//conf/conn.php
session_start();

$user = "root";
$pass = "";
$db = "adv_login";
$host = "localhost";

$db = new PDO('mysql:host=localhost;dbname='.$db.';charset=utf8',$user,$pass);

require_once("conf/library.php");
require_once("conf/ClassLogin.php");

$login = new Login();
2

Sekalian kita buat file logoutnya juga di direktori utama : logout.php.

<?php
//conf/conn.php
session_start();

$user = "root";
$pass = "";
$db = "adv_login";
$host = "localhost";

$db = new PDO('mysql:host=localhost;dbname='.$db.';charset=utf8',$user,$pass);

require_once("conf/library.php");
require_once("conf/ClassLogin.php");

$login = new Login();
3

 

 

SELESAI.. Kita akan cek satu per satu..

Pertama, metode Bruteforce nggak akan berjalan di halaman Log In ini.. Karena sudah ada fungsi cek_salah_login() yang akan langsung menutup akses login ketika sudah mencapai sekian kali kesalahan. Kedua, metode SQL Injection juga nggak akan berjalan. Karena kita menggunakan escaping ($db->quote), dan fungsi prepared statement di semua query yang ada. Ketiga, metode Session Hijacking juga nggak akan berjalan, karena cookie token yang diremember sekalipun disimpan untuk dicek IP dan User Agentnya. Sehingga apabila cookie tersebut dicuri sekalipun, karena IP dan User Agent yang berbeda login tidak dapat dilakukan juga.

Silakan dicoba, apakah sudah bisa berjalan atau tidak.. Kalau sudah stuck, dan masih nggak ketemu juga errornya dimana, silakan langsung download file jadinya saja di www.tianrosandhy.com/download/prompt/advance-secure-login.

Apa gunanya session di PHP?

Apa itu Session di PHP? Session adalah mekanisme untuk mempertahankan informasi di semua halaman web yang berbeda untuk mengidentifikasi pengguna saat mereka menelusuri situs atau aplikasi.

Dimana session PHP disimpan?

Berbeda dengan cookies yang disimpan di browser, session disimpan di dalam web server.

Bagaimana cara kerja session pada PHP?

Cara kerja Session: Saat pengunjung mengakses suatu halaman, pengunjung tersebut memulai session (digunakan fungsi session_start()). Bila dalam konfigurasi php, session.auto_start diset ke 1 maka php akan melakukan start session secara otomatis.

Bagaimana cara mengakhiri session pada PHP?

Untuk mengakhiri session pada PHP, kita gunakan perintah session_destroy() , dengan perintah ini maka file session akan dihapus dari server. contohnya ketika user logout, maka session akan berakhir dan user diminta untuk login kembali.