- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
13 KiB
13 KiB
Auth Module Configuration
Konfiguration und Setup für das Auth Module des Custom PHP Frameworks.
Dependency Injection Setup
Container Bindings
use App\Framework\Auth\PasswordHasher;
use App\Framework\Auth\AuthenticationService;
use App\Framework\Cryptography\KeyDerivationFunction;
// services.php oder Container Initialization
$container->singleton(PasswordHasher::class, function(Container $container) {
return new PasswordHasher(
kdf: $container->get(KeyDerivationFunction::class),
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);
});
$container->singleton(AuthenticationService::class, function(Container $container) {
return new AuthenticationService(
passwordHasher: $container->get(PasswordHasher::class),
sessionIdGenerator: $container->get(SessionIdGenerator::class),
repository: $container->get(AuthenticationRepository::class),
rateLimiter: $container->get(RateLimitService::class)
);
});
Environment Configuration
// .env Konfiguration
AUTH_SESSION_TIMEOUT=3600 # Session Timeout in Sekunden (1 Stunde)
AUTH_REMEMBER_TOKEN_EXPIRY=2592000 # Remember Token Expiry (30 Tage)
AUTH_MAX_LOGIN_ATTEMPTS=5 # Maximale Login-Versuche
AUTH_LOCKOUT_DURATION=900 # Account Lockout Duration (15 Minuten)
AUTH_RATE_LIMIT_WINDOW=300 # Rate Limit Window (5 Minuten)
# Password Hashing Configuration
AUTH_DEFAULT_ALGORITHM=argon2id # Standard Hash-Algorithmus
AUTH_DEFAULT_SECURITY_LEVEL=standard # low|standard|high
AUTH_PASSWORD_MIN_LENGTH=8 # Minimale Passwort-Länge
AUTH_PASSWORD_MAX_LENGTH=4096 # Maximale Passwort-Länge
# Session Security
AUTH_SESSION_REGENERATE_ON_LOGIN=true # Session ID bei Login regenerieren
AUTH_CHECK_IP_CONSISTENCY=false # IP-Konsistenz-Prüfung (optional)
AUTH_REMEMBER_TOKEN_LENGTH=32 # Remember Token Länge (Bytes)
Typed Configuration Class
final readonly class AuthConfig
{
public function __construct(
// Session Configuration
public int $sessionTimeout = 3600,
public int $rememberTokenExpiry = 2592000,
public bool $sessionRegenerateOnLogin = true,
public bool $checkIpConsistency = false,
public int $rememberTokenLength = 32,
// Security Configuration
public int $maxLoginAttempts = 5,
public int $lockoutDuration = 900,
public int $rateLimitWindow = 300,
// Password Configuration
public string $defaultAlgorithm = 'argon2id',
public string $defaultSecurityLevel = 'standard',
public int $passwordMinLength = 8,
public int $passwordMaxLength = 4096,
// Validation Configuration
public bool $enforcePasswordComplexity = true,
public bool $checkCommonPasswords = true,
public bool $preventSequentialChars = true,
public int $minPasswordScore = 50
) {}
public static function fromEnvironment(Environment $env): self
{
return new self(
sessionTimeout: $env->getInt(EnvKey::AUTH_SESSION_TIMEOUT, 3600),
rememberTokenExpiry: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_EXPIRY, 2592000),
sessionRegenerateOnLogin: $env->getBool(EnvKey::AUTH_SESSION_REGENERATE_ON_LOGIN, true),
checkIpConsistency: $env->getBool(EnvKey::AUTH_CHECK_IP_CONSISTENCY, false),
rememberTokenLength: $env->getInt(EnvKey::AUTH_REMEMBER_TOKEN_LENGTH, 32),
maxLoginAttempts: $env->getInt(EnvKey::AUTH_MAX_LOGIN_ATTEMPTS, 5),
lockoutDuration: $env->getInt(EnvKey::AUTH_LOCKOUT_DURATION, 900),
rateLimitWindow: $env->getInt(EnvKey::AUTH_RATE_LIMIT_WINDOW, 300),
defaultAlgorithm: $env->get(EnvKey::AUTH_DEFAULT_ALGORITHM, 'argon2id'),
defaultSecurityLevel: $env->get(EnvKey::AUTH_DEFAULT_SECURITY_LEVEL, 'standard'),
passwordMinLength: $env->getInt(EnvKey::AUTH_PASSWORD_MIN_LENGTH, 8),
passwordMaxLength: $env->getInt(EnvKey::AUTH_PASSWORD_MAX_LENGTH, 4096),
enforcePasswordComplexity: $env->getBool(EnvKey::AUTH_ENFORCE_PASSWORD_COMPLEXITY, true),
checkCommonPasswords: $env->getBool(EnvKey::AUTH_CHECK_COMMON_PASSWORDS, true),
preventSequentialChars: $env->getBool(EnvKey::AUTH_PREVENT_SEQUENTIAL_CHARS, true),
minPasswordScore: $env->getInt(EnvKey::AUTH_MIN_PASSWORD_SCORE, 50)
);
}
public function getSecurityLevelParameters(string $algorithm): array
{
return match ([$algorithm, $this->defaultSecurityLevel]) {
['argon2id', 'low'] => [
'memory_cost' => 32768, // 32 MB
'time_cost' => 2,
'threads' => 2
],
['argon2id', 'standard'] => [
'memory_cost' => 65536, // 64 MB
'time_cost' => 4,
'threads' => 3
],
['argon2id', 'high'] => [
'memory_cost' => 131072, // 128 MB
'time_cost' => 6,
'threads' => 4
],
['pbkdf2-sha256', 'low'] => ['iterations' => 50000],
['pbkdf2-sha256', 'standard'] => ['iterations' => 100000],
['pbkdf2-sha256', 'high'] => ['iterations' => 200000],
default => []
};
}
}
Database Schema
Required Tables
-- Benutzer-Tabelle (beispielhaft)
CREATE TABLE users (
id VARCHAR(255) PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
username VARCHAR(100) UNIQUE,
password_hash TEXT NOT NULL,
password_algorithm VARCHAR(50) NOT NULL DEFAULT 'argon2id',
password_parameters JSON,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
last_login_at DATETIME NULL,
is_active BOOLEAN DEFAULT TRUE,
INDEX idx_email (email),
INDEX idx_username (username),
INDEX idx_active (is_active)
);
-- Session-Tabelle
CREATE TABLE auth_sessions (
id VARCHAR(255) PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
ip_address VARCHAR(45),
user_agent TEXT,
created_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL,
last_activity DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_expires_at (expires_at),
INDEX idx_last_activity (last_activity)
);
-- Remember Token Tabelle
CREATE TABLE auth_remember_tokens (
token_hash VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_expires_at (expires_at)
);
-- Failed Login Attempts Tabelle
CREATE TABLE auth_failed_attempts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id VARCHAR(255),
identifier VARCHAR(255),
ip_address VARCHAR(45),
attempted_at DATETIME NOT NULL,
reason VARCHAR(100),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_id (user_id),
INDEX idx_identifier (identifier),
INDEX idx_ip_address (ip_address),
INDEX idx_attempted_at (attempted_at)
);
-- Security Events Tabelle (optional für Logging)
CREATE TABLE auth_security_events (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
event_type VARCHAR(50) NOT NULL,
user_id VARCHAR(255),
session_id VARCHAR(255),
ip_address VARCHAR(45),
user_agent TEXT,
event_data JSON,
created_at DATETIME NOT NULL,
INDEX idx_event_type (event_type),
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at),
INDEX idx_ip_address (ip_address)
);
Migration Commands
# Migration erstellen
php console.php make:migration CreateAuthTables Auth
# Migration ausführen
php console.php db:migrate
# Migration Status prüfen
php console.php db:status
Security Level Configuration
Password Hashing Levels
// Niedrige Sicherheit (Development, Testing)
$lowSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_LOW
);
// Standard Sicherheit (Production Default)
$standardSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_STANDARD
);
// Hohe Sicherheit (Banking, Healthcare)
$highSecurity = new PasswordHasher(
kdf: $kdf,
defaultAlgorithm: 'argon2id',
defaultSecurityLevel: PasswordHasher::LEVEL_HIGH
);
Algorithm Performance Comparison
| Algorithm | Level | Memory | Time | Iterations | Performance | Security |
|---|---|---|---|---|---|---|
| Argon2ID | Low | 32 MB | 2 | - | Fast | Good |
| Argon2ID | Standard | 64 MB | 4 | - | Medium | Excellent |
| Argon2ID | High | 128 MB | 6 | - | Slow | Maximum |
| PBKDF2-SHA256 | Low | - | - | 50,000 | Fast | Good |
| PBKDF2-SHA256 | Standard | - | - | 100,000 | Fast | Good |
| PBKDF2-SHA256 | High | - | - | 200,000 | Medium | Good |
| Scrypt | Standard | 16 MB | - | - | Medium | Good |
Rate Limiting Configuration
Redis-based Rate Limiting
use App\Framework\Auth\RateLimit\RedisRateLimitService;
$rateLimiter = new RedisRateLimitService(
redis: $redis,
config: new RateLimitConfig(
maxAttempts: 5,
windowSeconds: 300,
lockoutDuration: 900
)
);
File-based Rate Limiting
use App\Framework\Auth\RateLimit\FileRateLimitService;
$rateLimiter = new FileRateLimitService(
cacheDir: '/tmp/auth_rate_limits',
config: new RateLimitConfig(
maxAttempts: 5,
windowSeconds: 300,
lockoutDuration: 900,
cleanupInterval: 3600 // Cleanup alte Einträge jede Stunde
)
);
Monitoring & Logging
Security Event Configuration
// Security Event Handler
final readonly class SecurityEventHandler
{
public function __construct(
private Logger $logger,
private ?AlertingService $alerting = null
) {}
public function handle(SecurityEvent $event): void
{
// Log alle Security Events
$this->logger->warning('Security Event', [
'event_type' => $event->getType(),
'user_id' => $event->getUserId(),
'ip_address' => (string) $event->getIpAddress(),
'data' => $event->getData()
]);
// Kritische Events alarmieren
if ($event->isCritical()) {
$this->alerting?->sendAlert($event);
}
}
}
Performance Monitoring
// Performance Metrics für Password Hashing
$start = microtime(true);
$hashedPassword = $passwordHasher->hash($password);
$hashTime = microtime(true) - $start;
$this->metrics->histogram('auth.password_hash_duration', $hashTime, [
'algorithm' => $hashedPassword->getAlgorithm(),
'security_level' => $securityLevel
]);
Production Deployment
Environment-specific Configuration
// Production
AUTH_DEFAULT_SECURITY_LEVEL=high
AUTH_SESSION_TIMEOUT=1800 # 30 Minuten
AUTH_CHECK_IP_CONSISTENCY=true # Striktere IP-Prüfung
AUTH_MAX_LOGIN_ATTEMPTS=3 # Weniger Versuche
AUTH_LOCKOUT_DURATION=3600 # 1 Stunde Lockout
// Development
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=86400 # 24 Stunden
AUTH_CHECK_IP_CONSISTENCY=false
AUTH_MAX_LOGIN_ATTEMPTS=10
AUTH_LOCKOUT_DURATION=300 # 5 Minuten
// Testing
AUTH_DEFAULT_SECURITY_LEVEL=low
AUTH_SESSION_TIMEOUT=3600
AUTH_MAX_LOGIN_ATTEMPTS=5
AUTH_LOCKOUT_DURATION=60 # 1 Minute
Security Headers Configuration
// Middleware für Auth-bezogene Security Headers
final readonly class AuthSecurityHeadersMiddleware
{
public function handle(HttpRequest $request, callable $next): HttpResponse
{
$response = $next($request);
if ($request->getUri()->getPath() === '/login') {
$response = $response->withHeader('X-Frame-Options', 'DENY');
$response = $response->withHeader('X-Content-Type-Options', 'nosniff');
$response = $response->withHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
}
return $response;
}
}
Backup & Recovery
Session Cleanup
# Cron Job für Session Cleanup (täglich)
0 2 * * * php /path/to/console.php auth:cleanup-expired-sessions
# Manual Cleanup
php console.php auth:cleanup-expired-sessions
php console.php auth:cleanup-expired-tokens
Data Retention
// Cleanup Commands
final readonly class CleanupExpiredSessionsCommand
{
public function execute(): void
{
$expiredCount = $this->repository->deleteExpiredSessions();
$this->output->writeln("Deleted {$expiredCount} expired sessions");
$tokenCount = $this->repository->deleteExpiredRememberTokens();
$this->output->writeln("Deleted {$tokenCount} expired remember tokens");
$attemptCount = $this->repository->cleanupOldFailedAttempts(days: 30);
$this->output->writeln("Cleaned up {$attemptCount} old failed attempts");
}
}