Files
michaelschiemer/docs/components/cryptography/security.md
Michael Schiemer 55a330b223 Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
2025-08-11 20:13:26 +02:00

23 KiB

Cryptography Module - Sicherheitsrichtlinien

Detaillierte Sicherheitsrichtlinien und Best Practices für das Cryptography Module.

Grundlegende Sicherheitsprinzipien

Defense in Depth

Das Cryptography Module implementiert mehrschichtigen Schutz:

  1. Algorithmus-Ebene: Moderne, peer-reviewed Algorithmen (Argon2ID, SHA-3, ECDSA)
  2. Implementation-Ebene: Timing-sichere Operationen und sichere Speicherverwaltung
  3. Application-Ebene: Sichere Integration und Konfiguration
  4. System-Ebene: Sicherer Random Number Generator und Entropie-Validierung

Zero-Trust Architektur

// ✅ Vertraue niemals Eingaben - validiere alles
final readonly class SecureTokenValidator
{
    public function validateApiKey(string $providedKey): ?ApiKeyContext
    {
        // Eingabe-Validierung
        if (empty($providedKey) || strlen($providedKey) < 32) {
            return null;
        }
        
        // Format-Validierung
        if (!$this->tokenGenerator->isValidFormat($providedKey, 'base64_url')) {
            return null;
        }
        
        // Timing-sicherer Vergleich mit gespeichertem Hash
        $keyHash = hash('sha256', $providedKey);
        $storedKey = $this->repository->findByHash($keyHash);
        
        if (!$storedKey || !hash_equals($keyHash, $storedKey->getHash())) {
            return null;
        }
        
        // Zusätzliche Sicherheitsprüfungen
        return $this->performSecurityChecks($storedKey);
    }
}

Kryptographische Best Practices

Sichere Schlüssel-Ableitung

// ✅ Empfohlene Parameter für verschiedene Szenarien
final readonly class SecureKeyDerivation
{
    private const SECURITY_LEVELS = [
        // Hohe Sicherheit für sensitive Daten
        'high_security' => [
            'algorithm' => 'argon2id',
            'memory_cost' => 131072, // 128 MB
            'time_cost' => 6,        // 6 Iterationen
            'threads' => 4,          // 4 Threads
            'key_length' => 32       // 256 Bit
        ],
        
        // Standard für normale Anwendungen  
        'standard' => [
            'algorithm' => 'argon2id',
            'memory_cost' => 65536,  // 64 MB
            'time_cost' => 4,        // 4 Iterationen
            'threads' => 3,          // 3 Threads
            'key_length' => 32       // 256 Bit
        ],
        
        // Kompatibilität mit älteren Systemen
        'legacy_compatible' => [
            'algorithm' => 'pbkdf2-sha256',
            'iterations' => 200000,  // 200k Iterationen
            'key_length' => 32       // 256 Bit
        ]
    ];
    
    public function hashPassword(string $password, string $level = 'standard'): DerivedKey
    {
        $params = self::SECURITY_LEVELS[$level] ?? self::SECURITY_LEVELS['standard'];
        
        return match ($params['algorithm']) {
            'argon2id' => $this->kdf->argon2id(
                $password,
                $this->kdf->generateSalt(32),
                $params['memory_cost'],
                $params['time_cost'],
                $params['threads'],
                $params['key_length']
            ),
            'pbkdf2-sha256' => $this->kdf->pbkdf2(
                $password,
                $this->kdf->generateSalt(32),
                $params['iterations'],
                $params['key_length']
            )
        };
    }
}

Sichere Token-Generierung

// ✅ Token-Sicherheit nach Verwendungszweck
final readonly class SecurityAwareTokenGenerator
{
    private const TOKEN_SECURITY_REQUIREMENTS = [
        'api_key' => [
            'length' => 32,        // 256 Bit
            'format' => 'base64_url',
            'entropy_min' => 7.0,
            'expires' => false,    // Langlebig
            'single_use' => false
        ],
        
        'session' => [
            'length' => 48,        // 384 Bit (höhere Sicherheit)
            'format' => 'base64_url', 
            'entropy_min' => 7.5,
            'expires' => true,
            'single_use' => false
        ],
        
        'csrf' => [
            'length' => 32,        // 256 Bit
            'format' => 'base64_url',
            'entropy_min' => 7.0,
            'expires' => true,     // Kurze Lebensdauer
            'single_use' => true   // Einmalverwendung
        ],
        
        'password_reset' => [
            'length' => 64,        // 512 Bit (maximale Sicherheit)
            'format' => 'base64_url',
            'entropy_min' => 7.8,
            'expires' => true,
            'single_use' => true,
            'max_lifetime' => 3600 * 2 // 2 Stunden
        ]
    ];
    
    public function generateSecureToken(string $type): SecureToken
    {
        $requirements = self::TOKEN_SECURITY_REQUIREMENTS[$type] ?? 
                       throw new InvalidArgumentException("Unknown token type: {$type}");
        
        do {
            $token = $this->tokenGenerator->generate(
                $type,
                $requirements['length'],
                $requirements['format']
            );
            
            // Entropie validieren
            $entropy = $this->utils->calculateShannonEntropy($token->getRawBytes());
        } while ($entropy < $requirements['entropy_min']);
        
        return $token;
    }
}

Timing-Attack Prevention

Konstante Ausführungszeit

// ✅ Timing-sichere Implementierung
final readonly class TimingSafeOperations
{
    public function authenticateUser(string $email, string $password): ?User
    {
        $user = $this->userRepository->findByEmail(new Email($email));
        
        // WICHTIG: Immer Hashing durchführen, auch bei ungültigem User
        $providedHash = $user 
            ? $user->getPasswordHash() 
            : $this->createDummyHash(); // Konstante Ausführungszeit
        
        $isValid = $this->kdf->verify($password, $providedHash);
        
        // Zusätzliche konstante Verzögerung
        $this->enforceConstantTime();
        
        return $isValid && $user ? $user : null;
    }
    
    private function createDummyHash(): DerivedKey
    {
        // Dummy-Hash mit gleichen Parametern wie echte Hashes
        static $dummyHash = null;
        
        if ($dummyHash === null) {
            $dummyHash = $this->kdf->hashPassword('dummy-password', 'argon2id');
        }
        
        return $dummyHash;
    }
    
    private function enforceConstantTime(): void
    {
        // Minimale zusätzliche Verzögerung (1-5ms)
        usleep(random_int(1000, 5000));
    }
}

Side-Channel Resistance

// ✅ Schutz vor Side-Channel-Angriffen
final readonly class SideChannelResistantComparison
{
    public function compareSecrets(string $secret1, string $secret2): bool
    {
        // PHP's hash_equals ist timing-sicher implementiert
        return hash_equals($secret1, $secret2);
    }
    
    public function compareArrays(array $array1, array $array2): bool
    {
        // Arrays zu Strings serialisieren für timing-sicheren Vergleich
        $string1 = json_encode($array1, JSON_SORT_KEYS);
        $string2 = json_encode($array2, JSON_SORT_KEYS);
        
        return hash_equals($string1, $string2);
    }
    
    public function searchInArray(array $haystack, mixed $needle): bool
    {
        $found = false;
        
        // Alle Elemente durchgehen (konstante Zeit)
        foreach ($haystack as $value) {
            $isMatch = is_string($value) && is_string($needle)
                ? hash_equals($value, $needle)
                : ($value === $needle);
            
            $found = $found || $isMatch; // Kein frühes Beenden
        }
        
        return $found;
    }
}

Sichere Speicherverwaltung

Sensitive Data Handling

// ✅ Sicherer Umgang mit sensitiven Daten
final readonly class SecureMemoryManagement
{
    public function processSecretData(string $secretData): ProcessedResult
    {
        try {
            // Daten verarbeiten
            $result = $this->doSecretProcessing($secretData);
            
            // Sensitive Daten aus Speicher löschen
            $this->utils->secureWipe($secretData);
            
            return $result;
            
        } catch (Throwable $e) {
            // Auch bei Fehlern Speicher löschen
            $this->utils->secureWipe($secretData);
            throw $e;
        }
    }
    
    public function createSecureTemporaryFile(string $data): SecureTemporaryFile
    {
        // Temporary file mit restriktiven Berechtigungen erstellen
        $tempFile = tempnam(sys_get_temp_dir(), 'secure_');
        chmod($tempFile, 0600); // Nur Owner kann lesen/schreiben
        
        // Daten schreiben und sofort aus Speicher löschen
        file_put_contents($tempFile, $data);
        $this->utils->secureWipe($data);
        
        // Auto-cleanup mit Destruktor
        return new SecureTemporaryFile($tempFile);
    }
}

// Auto-cleanup für temporäre Dateien
final class SecureTemporaryFile
{
    public function __construct(private string $filePath) {}
    
    public function __destruct()
    {
        if (file_exists($this->filePath)) {
            // Datei mehrfach überschreiben vor dem Löschen
            $fileSize = filesize($this->filePath);
            
            for ($i = 0; $i < 3; $i++) {
                file_put_contents($this->filePath, random_bytes($fileSize));
            }
            
            unlink($this->filePath);
        }
    }
    
    public function getPath(): string
    {
        return $this->filePath;
    }
}

Input Validation und Sanitization

Comprehensive Input Validation

// ✅ Umfassende Eingabe-Validierung
final readonly class CryptographicInputValidator
{
    public function validatePasswordStrength(string $password): ValidationResult
    {
        $errors = [];
        
        // Länge prüfen
        if (strlen($password) < 8) {
            $errors[] = 'Password must be at least 8 characters long';
        }
        
        // Komplexität prüfen
        if (!preg_match('/[A-Z]/', $password)) {
            $errors[] = 'Password must contain uppercase letters';
        }
        
        if (!preg_match('/[a-z]/', $password)) {
            $errors[] = 'Password must contain lowercase letters';
        }
        
        if (!preg_match('/[0-9]/', $password)) {
            $errors[] = 'Password must contain numbers';
        }
        
        if (!preg_match('/[^A-Za-z0-9]/', $password)) {
            $errors[] = 'Password must contain special characters';
        }
        
        // Entropie prüfen
        $entropy = $this->utils->calculateShannonEntropy($password);
        if ($entropy < 3.5) {
            $errors[] = 'Password has insufficient entropy';
        }
        
        // Gegen Common-Passwords prüfen
        if ($this->isCommonPassword($password)) {
            $errors[] = 'Password is too common';
        }
        
        return new ValidationResult(empty($errors), $errors);
    }
    
    public function validateApiKeyFormat(string $apiKey): bool
    {
        // Länge prüfen (32-64 Zeichen)
        if (strlen($apiKey) < 32 || strlen($apiKey) > 64) {
            return false;
        }
        
        // Format prüfen (Base64URL)
        if (!preg_match('/^[A-Za-z0-9_-]+$/', $apiKey)) {
            return false;
        }
        
        // Entropie validieren
        $entropy = $this->utils->calculateShannonEntropy($apiKey);
        return $entropy >= 6.0;
    }
    
    public function sanitizeUserInput(string $input): string
    {
        // Whitespace normalisieren
        $sanitized = trim($input);
        
        // Null-Bytes entfernen (verhindern Directory Traversal)
        $sanitized = str_replace("\0", '', $sanitized);
        
        // Control Characters entfernen
        $sanitized = preg_replace('/[\x00-\x1F\x7F]/', '', $sanitized);
        
        return $sanitized;
    }
    
    private function isCommonPassword(string $password): bool
    {
        $commonPasswords = [
            'password', '123456', 'password123', 'admin', 'qwerty',
            'letmein', 'welcome', 'monkey', '1234567890', 'password1'
        ];
        
        $lowercase = strtolower($password);
        
        foreach ($commonPasswords as $common) {
            if ($lowercase === $common || 
                levenshtein($lowercase, $common) <= 2) {
                return true;
            }
        }
        
        return false;
    }
}

Rate Limiting und Abuse Prevention

Cryptographic Rate Limiting

// ✅ Rate-Limiting für kryptographische Operationen
final readonly class CryptographicRateLimiter
{
    private const LIMITS = [
        'password_attempts' => ['count' => 5, 'window' => 900],    // 5 in 15 Min
        'token_generation' => ['count' => 100, 'window' => 3600], // 100 in 1 Stunde
        'password_reset' => ['count' => 3, 'window' => 3600],     // 3 in 1 Stunde
        'otp_generation' => ['count' => 5, 'window' => 300],      // 5 in 5 Min
    ];
    
    public function __construct(
        private CacheInterface $cache,
        private SecurityEventLogger $securityLogger
    ) {}
    
    public function checkLimit(string $operation, string $identifier): bool
    {
        $limit = self::LIMITS[$operation] ?? null;
        
        if (!$limit) {
            return true; // Kein Limit definiert
        }
        
        $cacheKey = "ratelimit_{$operation}_{$identifier}";
        $attempts = $this->cache->get($cacheKey, []);
        $now = time();
        
        // Abgelaufene Versuche entfernen
        $attempts = array_filter($attempts, fn($timestamp) => 
            $now - $timestamp < $limit['window']);
        
        if (count($attempts) >= $limit['count']) {
            // Rate-Limit erreicht
            $this->securityLogger->logRateLimitExceeded($operation, $identifier);
            return false;
        }
        
        // Neuen Versuch hinzufügen
        $attempts[] = $now;
        $this->cache->set($cacheKey, $attempts, $limit['window']);
        
        return true;
    }
    
    public function recordFailedAttempt(string $operation, string $identifier): void
    {
        $cacheKey = "failed_{$operation}_{$identifier}";
        $failures = $this->cache->get($cacheKey, 0);
        $failures++;
        
        $this->cache->set($cacheKey, $failures, 3600); // 1 Stunde
        
        // Bei vielen Fehlversuchen Sicherheitsteam benachrichtigen
        if ($failures >= 10) {
            $this->securityLogger->logSuspiciousActivity(
                $operation, 
                $identifier, 
                "Multiple failed attempts: {$failures}"
            );
        }
    }
}

Error Handling und Information Leakage Prevention

Secure Error Handling

// ✅ Sichere Fehlerbehandlung ohne Information Leakage
final readonly class SecureErrorHandler
{
    public function handleCryptographicError(Throwable $error): ErrorResponse
    {
        // Detaillierte Logs für interne Analyse
        $this->logger->error('Cryptographic error occurred', [
            'error_type' => get_class($error),
            'message' => $error->getMessage(),
            'trace' => $error->getTraceAsString(),
            'context' => $this->getSecureContext()
        ]);
        
        // Generische Antwort für Client (keine Details)
        $publicMessage = match (true) {
            $error instanceof InvalidPasswordException => 'Authentication failed',
            $error instanceof TokenExpiredException => 'Token has expired',
            $error instanceof TokenInvalidException => 'Invalid token',
            $error instanceof CryptographicException => 'Security operation failed',
            default => 'Internal error occurred'
        };
        
        return new ErrorResponse(
            message: $publicMessage,
            code: $this->getPublicErrorCode($error),
            timestamp: new DateTimeImmutable()
        );
    }
    
    private function getSecureContext(): array
    {
        return [
            'request_id' => $this->generateRequestId(),
            'user_agent_hash' => hash('sha256', $_SERVER['HTTP_USER_AGENT'] ?? ''),
            'ip_hash' => hash('sha256', $_SERVER['REMOTE_ADDR'] ?? ''),
            'timestamp' => time()
        ];
    }
    
    private function generateRequestId(): string
    {
        return bin2hex(random_bytes(16));
    }
}

Monitoring und Alerting

Security Monitoring

// ✅ Sicherheits-Monitoring für kryptographische Operationen
final readonly class CryptographicSecurityMonitor
{
    public function __construct(
        private MetricsCollector $metrics,
        private AlertManager $alerts,
        private SecurityEventLogger $securityLogger
    ) {}
    
    public function monitorOperation(string $operation, callable $callback): mixed
    {
        $startTime = microtime(true);
        $operationId = bin2hex(random_bytes(8));
        
        try {
            $result = $callback();
            
            // Erfolgreiche Operation protokollieren
            $duration = microtime(true) - $startTime;
            $this->metrics->increment("crypto.{$operation}.success");
            $this->metrics->timing("crypto.{$operation}.duration", $duration);
            
            // Ungewöhnlich lange Operationen melden
            if ($duration > $this->getExpectedDuration($operation) * 2) {
                $this->alerts->sendAlert(
                    level: 'warning',
                    message: "Slow cryptographic operation: {$operation}",
                    context: ['duration' => $duration, 'operation_id' => $operationId]
                );
            }
            
            return $result;
            
        } catch (Throwable $e) {
            // Fehlgeschlagene Operation protokollieren
            $this->metrics->increment("crypto.{$operation}.failure");
            $this->securityLogger->logCryptographicFailure($operation, $e, $operationId);
            
            // Bei kritischen Fehlern sofort alarmieren
            if ($this->isCriticalError($e)) {
                $this->alerts->sendAlert(
                    level: 'critical',
                    message: "Critical cryptographic failure: {$operation}",
                    context: [
                        'error' => $e->getMessage(),
                        'operation_id' => $operationId
                    ]
                );
            }
            
            throw $e;
        }
    }
    
    public function detectAnomalousPatterns(): void
    {
        // Erhöhte Fehlerrate erkennen
        $errorRate = $this->metrics->getRate('crypto.*.failure', '5m');
        if ($errorRate > 0.1) { // >10% Fehlerrate
            $this->alerts->sendAlert(
                level: 'warning', 
                message: 'High cryptographic error rate detected',
                context: ['error_rate' => $errorRate]
            );
        }
        
        // Ungewöhnliche Aktivitätsmuster
        $operations = $this->metrics->getCount('crypto.*.success', '1h');
        $baseline = $this->getHistoricalBaseline();
        
        if ($operations > $baseline * 5) {
            $this->alerts->sendAlert(
                level: 'warning',
                message: 'Unusual spike in cryptographic operations',
                context: ['operations' => $operations, 'baseline' => $baseline]
            );
        }
    }
    
    private function getExpectedDuration(string $operation): float
    {
        return match ($operation) {
            'token_generation' => 0.001,    // 1ms
            'password_hash' => 0.5,         // 500ms (Argon2ID)
            'password_verify' => 0.5,       // 500ms
            'signature_create' => 0.01,     // 10ms
            'signature_verify' => 0.005,    // 5ms
            default => 0.1                  // 100ms
        };
    }
}

Compliance und Audit

Compliance Framework

// ✅ Compliance-Unterstützung für Regulierungen
final readonly class CryptographicComplianceValidator
{
    private const COMPLIANCE_REQUIREMENTS = [
        'GDPR' => [
            'encryption_required' => true,
            'key_length_min' => 256,
            'algorithm_approved' => ['AES-256-GCM', 'ChaCha20-Poly1305'],
            'key_rotation_days' => 365,
            'audit_trail_required' => true
        ],
        
        'PCI_DSS' => [
            'encryption_required' => true,
            'key_length_min' => 256,
            'algorithm_approved' => ['AES-256', 'RSA-2048'],
            'key_rotation_days' => 365,
            'secure_key_storage' => true
        ],
        
        'FIPS_140_2' => [
            'approved_algorithms_only' => true,
            'algorithm_approved' => ['AES', 'SHA-256', 'RSA', 'ECDSA'],
            'random_number_generator' => 'FIPS_approved',
            'key_length_min' => 256
        ]
    ];
    
    public function validateCompliance(string $standard): ComplianceReport
    {
        $requirements = self::COMPLIANCE_REQUIREMENTS[$standard] ?? 
                       throw new InvalidArgumentException("Unknown standard: {$standard}");
        
        $violations = [];
        $report = new ComplianceReport($standard);
        
        // Algorithmus-Compliance prüfen
        if (isset($requirements['algorithm_approved'])) {
            $usedAlgorithms = $this->getUsedAlgorithms();
            $approvedAlgorithms = $requirements['algorithm_approved'];
            
            foreach ($usedAlgorithms as $algorithm) {
                if (!in_array($algorithm, $approvedAlgorithms)) {
                    $violations[] = "Non-approved algorithm in use: {$algorithm}";
                }
            }
        }
        
        // Schlüssel-Längen prüfen
        if (isset($requirements['key_length_min'])) {
            $keyLengths = $this->getKeyLengths();
            $minLength = $requirements['key_length_min'];
            
            foreach ($keyLengths as $context => $length) {
                if ($length < $minLength) {
                    $violations[] = "Key length too short in {$context}: {$length} < {$minLength}";
                }
            }
        }
        
        // Schlüssel-Rotation prüfen
        if (isset($requirements['key_rotation_days'])) {
            $rotationViolations = $this->checkKeyRotation($requirements['key_rotation_days']);
            $violations = array_merge($violations, $rotationViolations);
        }
        
        $report->setViolations($violations);
        $report->setCompliant(empty($violations));
        
        return $report;
    }
    
    public function generateAuditReport(): AuditReport
    {
        return new AuditReport([
            'cryptographic_operations' => $this->getCryptoOperationStats(),
            'key_management' => $this->getKeyManagementStats(),
            'algorithm_usage' => $this->getAlgorithmUsageStats(),
            'security_events' => $this->getSecurityEventSummary(),
            'compliance_status' => $this->getComplianceStatus()
        ]);
    }
}

Diese Sicherheitsrichtlinien stellen sicher, dass das Cryptography Module höchste Sicherheitsstandards erfüllt und gegen moderne Angriffsvektoren geschützt ist.