Desain Login User dengan Cookie di PHP


Penasaran dengan penggunaan PHP (Personal Home Page) session yang mulai banyak artikel yang menyarankan untuk segera meninggalkan penggunaanya, penulis mencoba membuat desain login membership dengan cookie.

Salah satu latar belakangnya adalah jawaban Guidrevitch (2017), atas pertanyaan yang terkait alasan Wordpress yang meninggalkan PHP session untuk kebaikan di pihak server, di Quora.com, terutama untuk masalah performa Worpress.

Penulis bingung, sampai penulis menemukan tulisan dari Pasztor (2019), yang menegaskan untuk segera menghentikan penggunaan PHP session, dikarenakan PHP session merupakan sistem kunci, yang tidak mengunci sepenuhnya, dan dapat menjadi bom waktu, jika akses secara paralel dan dalam kuantitas yang banyak terjadi.

Hal itu dikarenakan PHP session masih menggunakan file system, yang perlu dibuka dan ditutup dahulu ketika akan menuliskan session yang lain.

Penulis sebenarnya masih belum mempercayainya, tetapi berdasarkan pengalaman penulis menggunakan Wordpress semenjak tahun 2015, sepertinya memang Wordpress sudah tidak menggunakan PHP session lagi.

Terbukti ketika penulis akan membutuhkan session, sekitar satu tahun sebelum tulisan ini ditulis, untuk keperluan plug-in membership di Wordpress, penulis perlu menambahkan session sendiri, yang dilakukan secara manual dan satu persatu.

Oleh karena itu, penulis yakin kalau memang PHP session sudah ditinggalkan, dan sudah saatnya menggunakan metode keamanan yang lain.

Berikut ini adalah ide penulis dalam menambahkan login membership pada website yang sedang penulis kerjakan.

SQL Database
Sudah pasti, karena data user disimpan dalam database, percobaan ini membutuhkan SQL database, dengan table user kurang lebih dengan struktur data seperti di bawah ini:

CREATE TABLE users (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    passcode VARCHAR(255) NOT NULL,
    passkey VARCHAR(255) NULL,
    userlevel INT(2) DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    login_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

Login Form
Kode login form yang digunakan adalah sebagai berikut:

<form id="loginForm" name="loginForm" method="post" action="login.php"> 
 <center> 
 <input type="text" name="userid" placeholder="NIK" value="<?php if(isset($_POST['userid']))echo $_POST['userid'];?>"/><br/> 
 <input type="password" name="passid" placeholder="password"/><br/> 
 <div class="g-recaptcha" data-sitekey="6Lfv2VwUAAAAAI56mr-opCEVe7omqf7sxguOz5FS"></div> 
 <input type="submit" value="Login"/> 
 </center> 
 </form> 

Login.php
Ketika action post diberikan, dan user memberikan username dan password yang benar, maka akan dilakukan registrasi cookie login_user dan login_key, dengan lama kadaluarsa setelah satu jam.

   $myusername = filter_var($_POST['userid'], FILTER_SANITIZE_STRING);
   $mypassword = md5(filter_var($_POST['passid'], FILTER_SANITIZE_STRING));
 
   $sql = "SELECT id FROM users WHERE username = '$myusername' AND passcode = '$mypassword'"; 
   $result = mysqli_query($dbconnection,$sql); 
   if($result){ 
    $row = mysqli_fetch_array($result,MYSQLI_ASSOC); 
    $id=$row['id']; 
    $count = mysqli_num_rows($result); 
    if($count == 1){ 
     $passkey=getRandomChar(rand(20,45)); 
     echo $passkey." ".$id; 
     $sql = "UPDATE users SET passkey = '$passkey',login_at=now() WHERE id='$id'"; 
     $result = mysqli_query($dbconnection,$sql); 
     if($result){ 
      setcookie("login_user",$myusername, time()+3600, "/"); 
      setcookie("login_key",$passkey, time()+3600, "/"); 
      header("Location:dashboard.php"); 
      die(); 
     }else{ 
      $ErrorMessage = "Unknown get timestap"; 
     } 
    }else { 
     $ErrorMessage = "Your login name or password is invalid"; 
    } 
   }else{ 
    $ErrorMessage=mysqli_error($dbconnection); 
   } 

Checklogin.php
Kode ini diperuntukkan untuk memvalidasi login user secara berkala, yaitu ketika memasuki halaman baru, user akan dicheck kesesuaian login_user dan login_key dengan di database.

Jika sesuai maka baik di database maupun cookie di client diperbaharui waktu kadaluarsanya.

if(isset($_COOKIE["login_user"]) && !empty($_COOKIE['login_user'])){ 
 $sql = "SELECT login_at,now() FROM users WHERE username = '".$_COOKIE["login_user"]."' AND passkey = '".$_COOKIE["login_key"]."'"; 
 $result = mysqli_query($dbconnection,$sql); 
 if($result){ 
  $count = mysqli_num_rows($result); 
  $row=mysqli_fetch_array($result); 
  if($count==1 && count($row)>2){ 
   $start_date = new DateTime($row[0]); 
   $since_start = $start_date->diff(new DateTime($row[1])); 
   $minutes = $since_start->days * 24 * 60; 
   $minutes += $since_start->h * 60; 
   $minutes += $since_start->i; 
   if($minutes>59){ 
    showErrorMessage("User login expired in server!"); 
   }else{ 
    $sql = "UPDATE users SET login_at=now() WHERE username = '".$_COOKIE["login_user"]."'"; 
    $result = mysqli_query($dbconnection,$sql); 
    if($result){ 
     setcookie("login_user",$_COOKIE["login_user"], time()+3600, "/"); 
     setcookie("login_key",$_COOKIE["login_key"], time()+3600, "/"); 
    }else showErrorMessage("Error at get time stamp!"); 
   } 
  }else{ 
   showErrorMessage("Seem you was login with another device!"); 
  } 
 } 
}else{ 
 header("Location:index.php"); 
} 

Logout.php
Halaman ini digunakan untuk membersihkan cookie yang telah teregistrasi.

session_start(); 
setcookie("login_user","", time()-3600, "/"); 
setcookie("login_key","", time()-3600, "/"); 
$_COOKIE['login_user']=""; 
session_destroy(); 

Skema kerja
Ketika user mengisi login form dan menekan tombol login, jika berhasil user akan diarahkan ke halaman dashboard.php, dengan meregistrasi dulu cookie login_user dan login_key.

Cookie login_key bukanlah digenerate dari password, tapi nilai ini berupa kumpulan angka dan huruf yang disusun dengan fungsi random dibawah ini:

function getRandomChar($n) { 
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $randomString = ''; 

    for ($i = 0; $i < $n; $i++) { 
        $index = rand(0, strlen($characters) - 1); 
        $randomString .= $characters[$index]; 
    } 

    return $randomString; 
} 

Sedangkan kedua cookie ini diset untuk kadaluarsa (expired) selama satu jam di sisi client.

Selain itu, experied juga di set di database, dengan menghitung selisih menit waktu login dan waktu sekarang dengan menggunakan fungsi diff di PHP DateTime.

Dengan juga menambahkan reCHAPTCA (seperti telah disebutkan dalam posting sebelumnya), kedua experied time ini ditujukan untuk mempertebal keamanan pengguna, tanpa menggunakan session.

Perlu diketahui, sistem yang penulis tawarkan disini, yaitu pengguna hanya dapat mengakses database melalui satu device saja.

Sehingga jika user berusaha login dengan device yang lain, hal tersebut akan mengubah nilai login_key, yang artinya login_key di device sebelumnya telah kadaluarsa.


Kecuali pengguna mau mencari nilai login_key terbaru, yang tersembunyi, yang kemudian sama-sama digunakan pada kedua device bersamaan.

Sebaliknya, jika user tidak bisa login, maka user akan tetap disuguhkan dengan login form, bersama dengan pesan error dari tahap login sebelumnya.

Bagian ceklogin.php diperuntukkan untuk validasi user, disetiap halaman yang membutuhkan autentifikasi seperti dashboard.php.

Artikel ini hanya desain penulis, menawarkan metode keamanan yang mungkin akan berbeda dengan yang penulis implementasi di kode penulis yang sebenarnya.

Setidaknya dalam tulisan ini, penulis telah menunjukkan login dapat dilakukan tanpa menggunakan session.

Referensi

  • Pasztor, Janos. 2019. Stop usinjg PHP sessions!. https://pasztor.at/blog/stop-using-php-sessions. Diakses tanggal 8 Desember 2019.
  • Guidrevitch, Aleksandr. 2017. Why does WordPress not use PHP session at all?. https://www.quora.com/Why-does-WordPress-not-use-PHP-session-at-all. Diakses tanggal 8 Desember 2019.

Komentar



Postingan populer dari blog ini

Apps Script untuk Cetak Sertifikat

Kebodohan Karyawan Menyalahkan Sistem

Kode Apps Script MailApp untuk Form Mengirimkan Email

Checking Data yang Belum Dimasukkan dalam Daftar Menggunakan Query Google Sheet

Generate Karakter Acak dan Menempatkannya di Sel Google Sheets dengan Apps Script

Menyembunyikan Failed Load Images di Blogger

Apps Script untuk Mengirimkan Notifikasi Approval

Algorithma Bilangan Prima dengan Javascript

Mencoba Submit Theme di Wordpress.org

Menghapus Baris di Google Sheets yang Memiliki Sel Kosong dengan Apps Script