Я создаю систему входа в систему и много читаю о мерах безопасности, необходимых для предотвращения перехвата сеансов, фиксации и атак с использованием инъекций и т. Д. Я определенно не эксперт по безопасности — я собрал воедино многие из них с помощью из сообщений на этом сайте и различных других. Эти два сообщения о переполнении стека были особенно полезны: Ссылка на сайт Ссылка 2
Прочитав их, я сделал много изменений и улучшений в моей системе, но я не уверен, что защищен от всего. Ниже то, что я придумал до сих пор. Я подозреваю, что некоторые из них будут правильными, некоторые из них будут неправильными, а некоторые могут быть лишними. Вот основной поток того, что происходит:
<?php
// convert password to hash
function passwordHash($string) {
return password_hash($string, PASSWORD_DEFAULT);
}
// compare password to hash
function passwordVerify($string, $hash) {
return password_verify($string, $hash);
}
// authenticate login password
function login($submitted_password, $password, $username) {
global $link;
if(passwordVerify($submitted_password, $password)) {
ini_set('session.use_trans_sid', FALSE);
ini_set('session.entropy_file', '/dev/urandom');
ini_set('session.hash_function', 'whirlpool');
ini_set('session.use_only_cookies', TRUE);
ini_set('session.cookie_httponly', TRUE);
ini_set('session.cookie_lifetime', 1200);
ini_set('session.cookie_secure', TRUE);
session_start();
$link->query("SELECT id, password, username, user_level FROM users WHERE username = :username");
$link->bind(':username', $username);
$link->execute();
$row = $link->getOneRow();
$link->closeStream();
$id = $row['id'];
$username = $row['username'];
$user_level = $row['user_level'];
$_SESSION['userID'] = $id;
$_SESSION['username'] = $username;
$_SESSION['user_level'] = $user_level;
$_SESSION['user_ip'] = $_SERVER['REMOTE_ADDR'];
$_SESSION['HTTP_USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
// store in db to use in page_protect()
$user_ip = $_SERVER['REMOTE_ADDR'];
$useragent_hash = passwordHash($_SESSION['HTTP_USER_AGENT']);
$link->query("UPDATE users SET user_ip = :user_ip, useragent_hash = :useragent_hash WHERE id = :id");
$link->bind(':user_ip', $user_ip);
$link->bind(':useragent_hash', $useragent_hash);
$link->bind(':id', $id);
$link->execute();
$link->closeStream();
header("Location: dashboard.php");
exit();
} else {
$error = "Username or password error"; // password fails
}
}
// function called by every page requiring you to be logged in
function page_protect() {
global $link;
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if(!isset($_SESSION['user_ip']) || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR']) {
logout();
exit();
}
// referenced in question #5 below
if (!isset($_SESSION['HTTP_USER_AGENT']) || $_SERVER['HTTP_USER_AGENT'] != $_SESSION['HTTP_USER_AGENT']) {
logout();
exit();
}
// check that IP address/useragent hash stored in db at login match current session variables
$link->query("SELECT useragent_hash, user_ip FROM users WHERE username = :username");
$link->bind(':username', $_SESSION['username']);
$link->execute();
$row = $link->getOneRow();
$link->closeStream();
$user_ip = $row['user_ip'];
$useragent_hash = $row['useragent_hash'];
if($_SESSION['user_ip'] != $user_ip || !passwordVerify($_SESSION['HTTP_USER_AGENT'], $useragent_hash)) {
logout();
exit();
}
session_regenerate_id(true);
}
function logout() {
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
unset($_SESSION);
session_unset();
session_destroy();
header("Location: index.php");
exit();
}
?>
1) Я что-то упускаю или что-то не так выглядит?
2) Я не уверен, что использую session_regenerate_id () в хорошем месте. Я знаю, что его нужно периодически вызывать, поэтому я подумал, что каждый раз, когда вызывается защищенная страница, будет хорошо.
3) Все ini_set в # 4 появляются только перед session_start () в функции входа в систему. Тем не менее, в верхней части каждой страницы, защищенной page_protect (), есть session_start (). Должны ли ему предшествовать все одинаковые ini_set на каждой странице, или как только они будут установлены во время первоначального входа, они останутся установленными?
4) Должен ли я удалить эту строку? ini_set (‘session.cookie_lifetime’, 1200); Это потребует от пользователя повторной регистрации через 20 минут. Я думаю, что было бы хорошо выйти из системы после 20 минут бездействия, но не после 20 минут перемещения по сайту.
5) В page_protect, когда я проверяю хэш ip и user agent, я должен использовать && вместо ||? Если оба условия соблюдены, что-то определенно не так.
Любая помощь с благодарностью.
Задача ещё не решена.
Других решений пока нет …