Security Hardening: Proaktive Kontosperren, Fail2Ban-Integration, SecurityLogger, Alerting und API-Schutz
This commit is contained in:
+50
-5
@@ -1613,6 +1613,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
dc_redirect('#sub-system-users');
|
||||
}
|
||||
|
||||
case 'unlock_user': {
|
||||
$userId = (int)($_POST['user_id'] ?? 0);
|
||||
if (Auth::unlockAccount($pdo, $userId)) {
|
||||
dc_flash('Benutzerkonto wurde erfolgreich entsperrt.');
|
||||
} else {
|
||||
dc_flash('Konto konnte nicht entsperrt werden oder existiert nicht.', 'danger');
|
||||
}
|
||||
dc_redirect('#sub-system-users');
|
||||
}
|
||||
|
||||
default:
|
||||
dc_flash('Unbekannte Aktion.', 'danger');
|
||||
dc_redirect();
|
||||
@@ -1869,12 +1879,19 @@ $releases = $updateManager->getReleases();
|
||||
// mitgelesen - er hat in der Ansicht nichts verloren.
|
||||
try {
|
||||
$users = $pdo->query('
|
||||
SELECT id, username, role, disabled, last_login_at, created_at
|
||||
SELECT id, username, role, disabled, failed_login_count, locked_until, last_login_at, created_at
|
||||
FROM dc_users ORDER BY role ASC, username ASC
|
||||
')->fetchAll() ?: [];
|
||||
} catch (Throwable $e) {
|
||||
// Vor Migration 012 fehlen role, disabled und last_login_at.
|
||||
$users = $pdo->query('SELECT id, username, created_at FROM dc_users ORDER BY username ASC')->fetchAll() ?: [];
|
||||
try {
|
||||
$users = $pdo->query('
|
||||
SELECT id, username, role, disabled, last_login_at, created_at
|
||||
FROM dc_users ORDER BY role ASC, username ASC
|
||||
')->fetchAll() ?: [];
|
||||
} catch (Throwable $e2) {
|
||||
// Vor Migration 012 fehlen role, disabled und last_login_at.
|
||||
$users = $pdo->query('SELECT id, username, created_at FROM dc_users ORDER BY username ASC')->fetchAll() ?: [];
|
||||
}
|
||||
}
|
||||
$usersSchemaReady = $users === [] || array_key_exists('role', $users[0]);
|
||||
|
||||
@@ -6285,8 +6302,11 @@ Antwort:
|
||||
$uRole = (string)($u['role'] ?? 'admin');
|
||||
$uDisabled = (int)($u['disabled'] ?? 0) === 1;
|
||||
$isSelf = (int)$u['id'] === Auth::userId();
|
||||
$isLocked = !empty($u['locked_until']) && strtotime((string)$u['locked_until'] . ' UTC') > time();
|
||||
$lockMins = $isLocked ? (int)ceil((strtotime((string)$u['locked_until'] . ' UTC') - time()) / 60) : 0;
|
||||
$failCount = (int)($u['failed_login_count'] ?? 0);
|
||||
?>
|
||||
<tr<?= $uDisabled ? ' style="opacity:0.55;"' : '' ?>>
|
||||
<tr<?= $uDisabled ? ' style="opacity:0.55;"' : ($isLocked ? ' style="background:rgba(239,68,68,0.08);"' : '') ?>>
|
||||
<td>
|
||||
<strong><?= e((string)$u['username']) ?></strong>
|
||||
<?php if ($isSelf): ?><span class="badge badge-up">Sie</span><?php endif; ?>
|
||||
@@ -6296,13 +6316,38 @@ Antwort:
|
||||
<?= e(strtoupper($uRole)) ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?= $uDisabled ? '<span class="badge badge-down">DEAKTIVIERT</span>' : 'aktiv' ?></td>
|
||||
<td>
|
||||
<?php if ($isLocked): ?>
|
||||
<span class="badge badge-down">GESPERRT (noch <?= $lockMins ?>m)</span>
|
||||
<?php elseif ($uDisabled): ?>
|
||||
<span class="badge badge-down">DEAKTIVIERT</span>
|
||||
<?php else: ?>
|
||||
<span style="color:var(--text-main);">aktiv</span>
|
||||
<?php endif; ?>
|
||||
<?php if ($failCount > 0 && !$isLocked): ?>
|
||||
<div style="font-size:0.75rem; color:var(--text-muted); margin-top:2px;">
|
||||
<?= $failCount ?> Fehlversuch(e)
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td style="font-size:0.8rem; color:var(--text-muted);">
|
||||
<?= !empty($u['last_login_at']) ? e((string)$u['last_login_at']) : 'nie' ?>
|
||||
</td>
|
||||
<td style="font-size:0.8rem; color:var(--text-muted);"><?= e((string)($u['created_at'] ?? '-')) ?></td>
|
||||
<td>
|
||||
<div style="display:flex; flex-wrap:wrap; gap:0.35rem;">
|
||||
<?php if ($isLocked): ?>
|
||||
<form method="POST" action="index.php" style="display:inline;">
|
||||
<?= $csrfField ?>
|
||||
<input type="hidden" name="action" value="unlock_user">
|
||||
<input type="hidden" name="_return" value="sub-system-users">
|
||||
<input type="hidden" name="user_id" value="<?= (int)$u['id'] ?>">
|
||||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
🔓 Entsperren
|
||||
</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="index.php" style="display:inline-flex; gap:0.25rem;"
|
||||
onsubmit="return confirm('Passwort für <?= e((string)$u['username']) ?> wirklich ändern?');">
|
||||
<?= $csrfField ?>
|
||||
|
||||
Reference in New Issue
Block a user