chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View File

@@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace App\Framework\Http\Session;
final readonly class CsrfProtection
{
private const int TOKEN_LIFETIME = 3600; //1h
private const int MAX_TOKENS_PER_FORM = 3;
private Session $session;
public function __construct(Session $session)
{
$this->session = $session;
// Sicherstellen, dass CSRF-Bereich existiert
if (!$this->session->has(SessionKey::CSRF->value)) {
$this->session->set(SessionKey::CSRF->value, []);
}
}
public function generateToken(string $formId): string
{
$token = bin2hex(random_bytes(32));
$csrf = $this->session->get(SessionKey::CSRF->value, []);
if (!isset($csrf[$formId])) {
$csrf[$formId] = [];
}
$csrf[$formId][] = [
'token' => $token,
'created_at' => time()
];
$csrf[$formId] = $this->cleanupOldTokens($csrf[$formId]);
$this->session->set(SessionKey::CSRF->value, $csrf);
return $token;
}
public function validateToken(string $formId, string $token): bool
{
$csrf = $this->session->get(SessionKey::CSRF->value, []);
if (!isset($csrf[$formId])) {
return false;
}
foreach ($csrf[$formId] as $index => $tokenData) {
if ($tokenData['token'] === $token) {
// Token ist gültig - NICHT löschen, nur als "used" markieren
$csrf[$formId][$index]['used_at'] = time();
$this->session->set(SessionKey::CSRF->value, $csrf);
return true;
}
}
return false;
}
private function cleanupOldTokens(array $tokens): array
{
$now = time();
$cleaned = [];
foreach ($tokens as $tokenData) {
// Behalte Token die:
// 1. Noch nicht abgelaufen sind
// 2. Kürzlich verwendet wurden (für Re-Submits)
$age = $now - $tokenData['created_at'];
$usedRecently = isset($tokenData['used_at']) &&
($now - $tokenData['used_at']) < 300; // 5 Minuten
if ($age < self::TOKEN_LIFETIME || $usedRecently) {
$cleaned[] = $tokenData;
}
}
// Behalte nur die neuesten N Tokens
return array_slice($cleaned, -self::MAX_TOKENS_PER_FORM);
}
// Diese Methode nur für spezielle Fälle behalten (z.B. AJAX)
/*public function renderHiddenFields(string $formId): string
{
$token = $this->generateToken($formId);
return sprintf(
'<input type="hidden" name="_token" value="%s"><input type="hidden" name="_form_id" value="%s">',
htmlspecialchars($token),
htmlspecialchars($formId)
);
}*/
}