Store persistent-login keys as SHA-256 hashes.
Each device now has its own row. Editors must log in again once after deploying.
This commit is contained in:
+35
-23
@@ -25,38 +25,48 @@ if (isset($_SERVER['HTTPS'])) {
|
||||
header( 'Pragma: no-cache' );
|
||||
}
|
||||
|
||||
/*
|
||||
* Persistent logins: the cookie holds "username|key", and the database
|
||||
* holds only a SHA-256 of the key, so a copy of the table cannot be used
|
||||
* to log in. Each device has its own row.
|
||||
*/
|
||||
function persistent_cookie() {
|
||||
$cookie_data = $_COOKIE['PersistentAuth'] ?? '';
|
||||
if (!is_string($cookie_data))
|
||||
$cookie_data = '';
|
||||
return explode("|", $cookie_data, 2) + array('', '');
|
||||
}
|
||||
|
||||
function persistent_key_hash($key) {
|
||||
return hash('sha256', $key);
|
||||
}
|
||||
|
||||
function check_persistent_login() {
|
||||
if (!array_key_exists('PersistentAuth', $_COOKIE)) {
|
||||
return false;
|
||||
}
|
||||
global $db, $is_admin;
|
||||
$table = "persistent_sessions";
|
||||
list($username, $key) = persistent_cookie();
|
||||
if ($username === '' || $key === '')
|
||||
return false;
|
||||
$key_hash = persistent_key_hash($key);
|
||||
|
||||
open_db('open');
|
||||
|
||||
$cookie_data = (string)$_COOKIE['PersistentAuth'];
|
||||
list($username, $key) = explode("|", $cookie_data, 2) + array('', '');
|
||||
|
||||
$query = "SELECT * FROM $table WHERE username = ? LIMIT 1";
|
||||
$getid = $db->execute_query($query, array($username)) or die("Query failed: ".$db->error);
|
||||
$query = "SELECT * FROM $table WHERE username = ? AND session = ? LIMIT 1";
|
||||
$getid = $db->execute_query($query, array($username, $key_hash)) or die("Query failed: ".$db->error);
|
||||
$row = $getid->fetch_assoc();
|
||||
open_db('close');
|
||||
|
||||
if (isset($row)) {
|
||||
// Set up session, and delete old cookie, and create new persistent cookie
|
||||
$stored_session = $row['session'];
|
||||
if ($stored_session == $key) {
|
||||
// login
|
||||
if (isset($row) && hash_equals((string)$row['session'], $key_hash)) {
|
||||
// Log in, then swap the used key for a new one
|
||||
login_editor($username);
|
||||
// delete cookie
|
||||
delete_persistent_login();
|
||||
// create new cookie
|
||||
create_persistent_login($username);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function create_persistent_login($username) {
|
||||
$validity = strtotime('+1 year'); // Time to keep the session valid
|
||||
@@ -64,11 +74,11 @@ function create_persistent_login($username) {
|
||||
$table = "persistent_sessions";
|
||||
open_db('open');
|
||||
|
||||
$key = bin2hex(random_bytes(100));
|
||||
$key = bin2hex(random_bytes(32));
|
||||
|
||||
// Add session key to database
|
||||
// Add the hash of the session key to the database
|
||||
$query = "INSERT INTO $table (username, session) VALUES (?, ?)";
|
||||
$db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error);
|
||||
$db->execute_query($query, array($username, persistent_key_hash($key))) or die("Query failed: ".$db->error);
|
||||
open_db('close');
|
||||
|
||||
// Create cookie with key
|
||||
@@ -82,16 +92,18 @@ function delete_persistent_login() {
|
||||
$table = "persistent_sessions";
|
||||
open_db('open');
|
||||
|
||||
$cookie_data = (string)($_COOKIE['PersistentAuth'] ?? '');
|
||||
list($username, $key) = explode("|", $cookie_data, 2) + array('', '');
|
||||
list($username, $key) = persistent_cookie();
|
||||
|
||||
// Remove this session key from the database
|
||||
if ($username !== '' && $key !== '') {
|
||||
$query = "DELETE FROM $table WHERE username = ? AND session = ?";
|
||||
$db->execute_query($query, array($username, $key)) or die("Query failed: ".$db->error);
|
||||
$db->execute_query($query, array($username, persistent_key_hash($key))) or die("Query failed: ".$db->error);
|
||||
}
|
||||
|
||||
// Reap old sessions
|
||||
// Reap old sessions, and keys stored before they were hashed
|
||||
$query = "DELETE FROM $table " .
|
||||
" WHERE created < DATE_SUB(now(), INTERVAL 1 YEAR);";
|
||||
" WHERE created < DATE_SUB(now(), INTERVAL 1 YEAR)" .
|
||||
" OR CHAR_LENGTH(session) <> 64;";
|
||||
$db->query($query) or die("Query failed: ".$db->error);
|
||||
|
||||
open_db('close');
|
||||
|
||||
Reference in New Issue
Block a user