1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
<?php
// Authorization class
// Maintains user's logged-in state and security of application
//
class Authorization
{
private $authorized;
private $login_failed;
private $system_password_encrypted;
public function __construct()
{
// first, make sure a CSRF token is generated
$this->generateToken();
// second, check for possible CSRF attacks. to protect logins, this is done before checking login
$this->checkToken();
// the salt and password encrypting is probably unnecessary protection but is done just
// for the sake of being very secure
if(!isset($_SESSION[COOKIENAME.'_salt']) && !isset($_COOKIE[COOKIENAME.'_salt']))
{
// create a random salt for this session if a cookie doesn't already exist for it
$_SESSION[COOKIENAME.'_salt'] = self::generateSalt(22);
}
else if(!isset($_SESSION[COOKIENAME.'_salt']) && isset($_COOKIE[COOKIENAME.'_salt']))
{
// session doesn't exist, but cookie does so grab it
$_SESSION[COOKIENAME.'_salt'] = $_COOKIE[COOKIENAME.'_salt'];
}
// salted and encrypted password used for checking
$this->system_password_encrypted = md5(SYSTEMPASSWORD."_".$_SESSION[COOKIENAME.'_salt']);
$this->authorized =
// no password
SYSTEMPASSWORD == ''
// correct password stored in session
|| isset($_SESSION[COOKIENAME.'password']) && hash_equals($_SESSION[COOKIENAME.'password'], $this->system_password_encrypted)
// correct password stored in cookie
|| isset($_COOKIE[COOKIENAME]) && isset($_COOKIE[COOKIENAME.'_salt']) && hash_equals(md5(SYSTEMPASSWORD."_".$_COOKIE[COOKIENAME.'_salt']), $_COOKIE[COOKIENAME]);
}
public function attemptGrant($password, $remember)
{
$hashed_password = crypt(SYSTEMPASSWORD, '$2a$07$'.self::generateSalt(22).'$');
if (hash_equals($hashed_password, crypt($password, $hashed_password))) {
if ($remember) {
// user wants to be remembered, so set a cookie
$expire = time()+60*60*24*30; //set expiration to 1 month from now
setcookie(COOKIENAME, $this->system_password_encrypted, $expire, null, null, null, true);
setcookie(COOKIENAME."_salt", $_SESSION[COOKIENAME.'_salt'], $expire, null, null, null, true);
} else {
// user does not want to be remembered, so destroy any potential cookies
setcookie(COOKIENAME, "", time()-86400, null, null, null, true);
setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true);
unset($_COOKIE[COOKIENAME]);
unset($_COOKIE[COOKIENAME.'_salt']);
}
$_SESSION[COOKIENAME.'password'] = $this->system_password_encrypted;
$this->authorized = true;
return true;
}
$this->login_failed = true;
return false;
}
public function revoke()
{
//destroy everything - cookies and session vars
setcookie(COOKIENAME, "", time()-86400, null, null, null, true);
setcookie(COOKIENAME."_salt", "", time()-86400, null, null, null, true);
unset($_COOKIE[COOKIENAME]);
unset($_COOKIE[COOKIENAME.'_salt']);
session_unset();
session_destroy();
$this->authorized = false;
// start a new session and generate a new CSRF token for the login form
session_start();
$this->generateToken();
}
public function isAuthorized()
{
return $this->authorized;
}
public function isFailedLogin()
{
return $this->login_failed;
}
public function isPasswordDefault()
{
return SYSTEMPASSWORD == 'admin';
}
private static function generateSalt($saltSize)
{
$set = 'ABCDEFGHiJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$setLast = strlen($set) - 1;
$salt = '';
while ($saltSize-- > 0) {
$salt .= $set[mt_rand(0, $setLast)];
}
return $salt;
}
private function generateToken()
{
// generate CSRF token
if (empty($_SESSION[COOKIENAME.'token']))
{
if (function_exists('random_bytes')) // introduced in PHP 7.0
{
$_SESSION[COOKIENAME.'token'] = bin2hex(random_bytes(32));
}
elseif (function_exists('openssl_random_pseudo_bytes')) // introduced in PHP 5.3.0
{
$_SESSION[COOKIENAME.'token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
else
{
// For PHP 5.2.x - This case can be removed once we drop support for 5.2.x
$_SESSION[COOKIENAME.'token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
}
}
}
private function checkToken()
{
// checking CSRF token
if($_SERVER['REQUEST_METHOD'] === 'POST' || isset($_GET['download'])) // all POST forms need tokens! downloads are protected as well
{
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['token']))
$check_token=$_POST['token'];
elseif($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['token']))
$check_token=$_GET['token'];
if (!isset($check_token))
{
die("CSRF token missing");
}
elseif(!hash_equals($_SESSION[COOKIENAME.'token'], $check_token))
{
die("CSRF token is wrong - please try to login again");
}
}
}
}
|