- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
430 lines
13 KiB
Markdown
430 lines
13 KiB
Markdown
# Auth Module Configuration
|
|
|
|
**Konfiguration und Setup** für das Auth Module des Custom PHP Frameworks.
|
|
|
|
## Dependency Injection Setup
|
|
|
|
### Container Bindings
|
|
|
|
```php
|
|
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
|
|
|
|
```php
|
|
// .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
|
|
|
|
```php
|
|
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
|
|
|
|
```sql
|
|
-- 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```php
|
|
// 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
|
|
|
|
```php
|
|
use App\Framework\Auth\RateLimit\RedisRateLimitService;
|
|
|
|
$rateLimiter = new RedisRateLimitService(
|
|
redis: $redis,
|
|
config: new RateLimitConfig(
|
|
maxAttempts: 5,
|
|
windowSeconds: 300,
|
|
lockoutDuration: 900
|
|
)
|
|
);
|
|
```
|
|
|
|
### File-based Rate Limiting
|
|
|
|
```php
|
|
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
|
|
|
|
```php
|
|
// 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
|
|
|
|
```php
|
|
// 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
|
|
|
|
```php
|
|
// 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
|
|
|
|
```php
|
|
// 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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```php
|
|
// 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");
|
|
}
|
|
} |