admin: csrf refactoring

This commit is contained in:
E. S. 2024-03-09 17:18:16 +00:00
parent 96236f66d3
commit 8938276d64
5 changed files with 51 additions and 42 deletions

View File

@ -214,14 +214,13 @@ function input(string $input, array $options = []): array {
return $ret;
}
function csrf_get(string $key): string { return _csrf_get_token($_SERVER['REMOTE_ADDR'], $key); }
function csrf_check(string $key) {
if (csrf_get($key) != ($_REQUEST['token'] ?? '')) {
forbidden('invalid token');
}
function csrf_get(string $key): string {
global $AdminSession, $config;
$user_key = is_admin() ? $AdminSession->csrfSalt : $_SERVER['REMOTE_ADDR'];
return substr(hash('sha256', $config['csrf_token'].$user_key.$key), 0, 20);
}
function _csrf_get_token(string $user_token, string $key): string {
global $config;
return substr(sha1($config['csrf_token'].$user_token.$key), 0, 20);
function csrf_check(string $key) {
if (csrf_get($key) != ($_REQUEST['token'] ?? ''))
forbidden('invalid token');
}

View File

@ -14,10 +14,11 @@ class AdminHandler extends request_handler {
}
function GET_index() {
$admin_info = admin_current_info();
global $AdminSession;
//$admin_info = admin_current_info();
set_title('$admin_title');
render('admin/index',
admin_login: $admin_info['login']);
admin_login: $AdminSession->login);
}
function GET_login() {

View File

@ -23,6 +23,8 @@ class Logger {
protected static ?array $classes = null;
public static function record(BaseAction $action): int {
global $AdminSession;
$packed = self::pack($action);
$data = [
@ -36,7 +38,7 @@ class Logger {
];
} else {
$data += [
'admin_id' => admin_current_info()['id'],
'admin_id' => $AdminSession->id,
'ip' => !empty($_SERVER['REMOTE_ADDR']) ? ip2ulong($_SERVER['REMOTE_ADDR']) : 0,
];
}

View File

@ -4,25 +4,31 @@ const ADMIN_SESSION_TIMEOUT = 86400 * 14;
const ADMIN_COOKIE_NAME = 'admin_key';
const ADMIN_LOGIN_MAX_LENGTH = 32;
$AdminSession = [
'id' => null,
'auth_id' => 0,
'login' => null,
];
$AdminSession = new class {
public function __construct(
public ?int $id = null,
public ?int $authId = null,
public ?string $csrfSalt = null,
public ?string $login = null,
) {}
public function mrProper(): void {
$this->id = null;
$this->authId = null;
$this->csrfSalt = null;
$this->login = null;
}
public function makeCSRFSalt(string $salted_password): void {
$this->csrfSalt = salt_password(strrev($salted_password));
}
};
function is_admin(): bool {
global $AdminSession;
if ($AdminSession['id'] === null)
if ($AdminSession->id === null)
_admin_check();
return $AdminSession['id'] != 0;
}
function admin_current_info(): array {
global $AdminSession;
return [
'id' => $AdminSession['id'],
'login' => $AdminSession['login']
];
return $AdminSession->id != 0;
}
function admin_exists(string $login): bool {
@ -63,7 +69,8 @@ function admin_auth(string $login, string $password): bool {
global $AdminSession;
$db = DB();
$q = $db->query("SELECT id FROM admins WHERE login=? AND password=?", $login, salt_password($password));
$salted_password = salt_password($password);
$q = $db->query("SELECT id FROM admins WHERE login=? AND password=?", $login, $salted_password);
if (!$db->numRows($q))
return false;
@ -79,6 +86,7 @@ function admin_auth(string $login, string $password): bool {
'token' => $token,
'ts' => $time
]);
$auth_id = $db->insertId();
$db->insert('admin_log', [
'admin_id' => $id,
@ -87,10 +95,10 @@ function admin_auth(string $login, string $password): bool {
'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '',
]);
$AdminSession = [
'id' => $id,
'login' => $login,
];
$AdminSession->id = $id;
$AdminSession->login = $login;
$AdminSession->makeCSRFSalt($salted_password);
$AdminSession->authId = $auth_id;
_admin_set_cookie($token);
return true;
@ -101,14 +109,11 @@ function admin_logout() {
return;
global $AdminSession;
$db = DB();
$db->query("DELETE FROM admin_auth WHERE id=?", $AdminSession->authId);
$db->query("DELETE FROM admin_auth WHERE id=?", $AdminSession['auth_id']);
$AdminSession['id'] = null;
$AdminSession['login'] = null;
$AdminSession['auth_id'] = 0;
$AdminSession->mrProper();
_admin_unset_cookie();
}
@ -125,6 +130,7 @@ function _admin_check(): void {
$q = $db->query("SELECT
admin_auth.id AS auth_id,
admin_auth.admin_id AS id,
admins.password AS salted_password,
admins.login AS login
FROM admin_auth
LEFT JOIN admins ON admin_auth.admin_id=admins.id
@ -137,9 +143,10 @@ function _admin_check(): void {
$info = $db->fetch($q);
global $AdminSession;
$AdminSession['id'] = (int)$info['id'];
$AdminSession['login'] = $info['login'];
$AdminSession['auth_id'] = (int)$info['auth_id'];
$AdminSession->id = (int)$info['id'];
$AdminSession->login = $info['login'];
$AdminSession->authId = (int)$info['auth_id'];
$AdminSession->makeCSRFSalt($info['salted_password']);
}
function _admin_set_cookie(string $token): void {

View File

@ -49,10 +49,10 @@ return [$html, $js];
function index($ctx, $admin_login) {
return <<<HTML
<div class="admin-page">
Authorized as <b>{$admin_login}</b><br>
Authorized as <b>{$admin_login}</b> | <a href="/admin/logout/?token={$ctx->csrf('logout')}">Sign out</a><br>
<!--<a href="/admin/log/">Log</a><br/>-->
<a href="/admin/uploads/">Uploads</a><br>
<a href="/admin/logout/?token={$ctx->csrf('logout')}">Sign out</a>
</div>
HTML;
}