- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
23 KiB
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:
- Algorithmus-Ebene: Moderne, peer-reviewed Algorithmen (Argon2ID, SHA-3, ECDSA)
- Implementation-Ebene: Timing-sichere Operationen und sichere Speicherverwaltung
- Application-Ebene: Sichere Integration und Konfiguration
- 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.