Add user verification requirement and is_admin field for enhanced security

This commit is contained in:
Fabian Schieder 2026-02-28 22:13:17 +01:00
parent cd047d057f
commit 05a0c7bb78
3 changed files with 32 additions and 15 deletions

View File

@ -14,19 +14,18 @@ try {
$r = adminer_app_try_register($username, $password, $password);
if (!empty($r['ok'])) {
echo "REGISTER OK\n";
echo "REGISTER OK (needs verification)\n";
} else {
echo "REGISTER FAIL: " . ($r['error'] ?? 'unknown') . "\n";
}
$l = adminer_app_try_login($username, $password);
if (!empty($l['ok'])) {
echo "LOGIN OK\n";
echo "LOGIN OK (unexpected)\n";
} else {
echo "LOGIN FAIL: " . ($l['error'] ?? 'unknown') . "\n";
echo "LOGIN BLOCKED: " . ($l['error'] ?? 'unknown') . "\n";
}
} catch (Throwable $e) {
echo "EXCEPTION: " . $e->getMessage() . "\n";
exit(1);
}

View File

@ -45,12 +45,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') ==
(string)($_POST['password2'] ?? '')
);
if (!empty($res['ok'])) {
$lr = adminer_app_try_login((string)($_POST['username'] ?? ''), (string)($_POST['password'] ?? ''));
if (!empty($lr['ok'])) {
header('Location: /adminer', true, 302);
exit;
}
$appRegOk = 'Konto erstellt! Bitte einloggen.';
$appRegOk = 'Konto erstellt. Bitte lasse dich von einem Server-Administrator verifizieren, bevor du dich anmelden kannst.';
$appPage = 'login';
} else {
$appRegError = (string)($res['error'] ?? 'Registrierung fehlgeschlagen.');

View File

@ -79,10 +79,22 @@ function adminer_app_bootstrap()
. 'id INT AUTO_INCREMENT PRIMARY KEY,'
. 'username VARCHAR(190) NOT NULL UNIQUE,'
. 'password_hash VARCHAR(255) NOT NULL,'
. 'is_admin TINYINT(1) NOT NULL DEFAULT 0,'
. 'created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP'
. ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
);
// Migration: falls Tabelle bereits existiert (alte Version ohne is_admin)
try {
$col = $pdo->query("SHOW COLUMNS FROM adminer_users LIKE 'is_admin'")->fetch();
if (!$col) {
$pdo->exec('ALTER TABLE adminer_users ADD COLUMN is_admin TINYINT(1) NOT NULL DEFAULT 0');
}
} catch (Throwable $e) {
// Wenn ALTER scheitert, lieber deutlich machen
throw new RuntimeException('Konnte adminer_users nicht migrieren (is_admin): ' . $e->getMessage());
}
// Optional: auto-seed from .env ADMINER_APP_SEED_USER/PASS
$vars = env_load(dirname(__DIR__) . '/.env');
$seedUser = env_get($vars, 'ADMINER_APP_SEED_USER', '');
@ -91,11 +103,15 @@ function adminer_app_bootstrap()
if ($seedUser !== '' && $seedPass !== '') {
$stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?');
$stmt->execute([(string)$seedUser]);
$exists = (bool)$stmt->fetchColumn();
if (!$exists) {
$id = $stmt->fetchColumn();
if (!$id) {
$hash = password_hash((string)$seedPass, PASSWORD_DEFAULT);
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash) VALUES (?, ?)');
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash, is_admin) VALUES (?, ?, 1)');
$ins->execute([(string)$seedUser, $hash]);
} else {
// sicherstellen, dass Seed-User Admin ist
$upd = $pdo->prepare('UPDATE adminer_users SET is_admin = 1 WHERE id = ?');
$upd->execute([(int)$id]);
}
}
}
@ -128,7 +144,7 @@ function adminer_app_try_login($username, $password)
}
$pdo = adminer_app_pdo();
$stmt = $pdo->prepare('SELECT id, password_hash FROM adminer_users WHERE username = ?');
$stmt = $pdo->prepare('SELECT id, password_hash, is_admin FROM adminer_users WHERE username = ?');
$stmt->execute([$username]);
$row = $stmt->fetch();
@ -136,12 +152,18 @@ function adminer_app_try_login($username, $password)
return ['ok' => false, 'error' => 'Login fehlgeschlagen.'];
}
// Erst nach Verifizierung erlauben
if (empty($row['is_admin'])) {
return ['ok' => false, 'error' => 'Dein Konto ist noch nicht verifiziert. Bitte lasse dich von einem Server-Administrator freischalten.'];
}
adminer_app_session_start();
if (PHP_SAPI !== 'cli') {
$_SESSION['adminer_app'] = [
'ok' => true,
'username' => $username,
'uid' => (int)$row['id'],
'is_admin' => (bool)$row['is_admin'],
];
}
@ -182,8 +204,9 @@ function adminer_app_try_register($username, $password, $password2)
return ['ok' => false, 'error' => 'Benutzername ist bereits vergeben.'];
}
// Standard: unverifiziert (is_admin=0)
$hash = password_hash($password, PASSWORD_DEFAULT);
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash) VALUES (?, ?)');
$ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash, is_admin) VALUES (?, ?, 0)');
$ins->execute([trim((string)$username), $hash]);
return ['ok' => true, 'error' => null];