My user authorization process looks like that.
During signin process function fires following code.
$token = sha1(microtime(true) . mt_rand(10000, 90000));
setcookie('auth', $token, $timeout);
Then adds generated token into database table right after user id column. BTW, in both $_SESSION and $_COOKIE storing only $token value.
There is another function named protect that comes at the top of every page and checks if cookies exist:
- at first checks db table for
$token: if there is no user with this token, signs out - Then checks
$_SERVER['HTTP_USER_AGENT'],$_SERVER['REMOTE_ADDR']with ones that stored in db tables.
Question
I feel that this is not secure way, because if attacker uses same PC and same browser, can get access simply by "copying-pasting" cookies. Also $_SERVER['REMOTE_ADDR'] doesn't always work.
How can I make this login more secure?
Detailed
Here is function protect
public function protect() {
if (!isset($_SESSION)) {
session_start();
}
$data = array();
if (isset($_SESSION['auth'])) {
$stmt = $this->db->prepare("SELECT l.browser, l.ip, u.ban from log AS l, users AS u WHERE l.token =? AND u.id=l.user_id LIMIT 1") or die($this->db->error);
$stmt->bind_param("i", $_SESSION['auth']) or die($stmt->error);
$stmt->execute() or die($stmt->error);
$stmt->store_result();
if ($stmt->num_rows == 0) {
$this->signout();
}
$stmt->bind_result($data['browser'], $data['ip'], $data['ban']);
$stmt->fetch() or die($stmt->error);
$stmt->close() or die($stmt->error);
$this->validation->check("protection", $data);
} else {
if (!isset($_COOKIE['auth'])) {
header('Location:' . wsurl);
}
$stmt = $this->db->prepare("SELECT l.browser, l.timeout, l.ip, u.ban from log AS l, users AS u where l.token =? AND u.id=l.user_id LIMIT 1") or die($this->db->error);
$stmt->bind_param("s", $_COOKIE['auth']) or die($stmt->error);
$stmt->execute() or die($stmt->error);
$stmt->store_result();
if ($stmt->num_rows == 0) {
$this->signout();
}
$stmt->bind_result($data['browser'], $data['timeout'], $data['ip'], $data['ban']) or die($stmt->error);
$stmt->fetch() or die($stmt->error);
$this->validation->check("protection", $data);
session_regenerate_id();
$_SESSION['auth'] = $_COOKIE['auth'];
$stmt->close() or die($stmt->error);
}
}
And Validation checks this
if ($data['browser'] != md5($_SERVER['HTTP_USER_AGENT'])) {
$this->registration->signout();
}
if ($data['ban'] == 1) {
$this->registration->signout(false);
header('Location:' . wsurl . "?page=msg&id=34");
}
if ($data['ip'] != $this->common->getIP("long")) {
$this->registration->signout();
}
if (isset($data['timeout']) && !empty($data['timeout'])) {
if (($data['timeout'] - $this->common->getTime()) < 0) {
$this->registration->signout();
}
}