# Request Signing > **Dokumentationshinweis:** Diese Dokumentation ist vollständig aktualisiert und stellt die aktuelle Implementierung des Request Signing korrekt dar. ## Übersicht Request Signing ist ein Sicherheitsmechanismus, der die Authentizität und Integrität von HTTP-Anfragen gewährleistet. Durch die kryptografische Signierung von Anfragen können Empfänger überprüfen, dass die Anfrage von einem autorisierten Absender stammt und während der Übertragung nicht manipuliert wurde. Das Framework bietet eine robuste Implementierung von Request Signing, die sowohl für ausgehende als auch für eingehende Anfragen verwendet werden kann. ## Hauptkomponenten ### RequestSigningService Die `RequestSigningService`-Klasse ist die zentrale Komponente für Request Signing: ```php use App\Framework\Security\RequestSigning\RequestSigningService; // Service initialisieren $service = new RequestSigningService( $signer, $verifier, $keyRepository, $config, $logger ); // Ausgehende Anfrage signieren $signedRequest = $service->signOutgoingRequest($request, $keyId); // Eingehende Anfrage verifizieren $result = $service->verifyIncomingRequest($request); if (!$result->isSuccess()) { throw new SecurityException('Ungültige Anfrage-Signatur: ' . $result->errorMessage); } ``` ### SigningKey Die `SigningKey`-Klasse repräsentiert einen kryptografischen Schlüssel für das Signieren von Anfragen: ```php use App\Framework\Security\RequestSigning\SigningKey; use App\Framework\Security\RequestSigning\SigningAlgorithm; // HMAC-Schlüssel generieren $hmacKey = SigningKey::generateHmac( 'api-key-1', SigningAlgorithm::HMAC_SHA256, new \DateTimeImmutable('+30 days') // Ablaufdatum ); // RSA-Schlüssel erstellen $privateKey = file_get_contents('private_key.pem'); $rsaKey = SigningKey::createRsa( 'api-key-2', $privateKey, new \DateTimeImmutable('+1 year') // Ablaufdatum ); ``` ### SigningAlgorithm Das `SigningAlgorithm`-Enum definiert die unterstützten Signaturalgorithmen: ```php use App\Framework\Security\RequestSigning\SigningAlgorithm; // Verfügbare Algorithmen $algorithm = SigningAlgorithm::HMAC_SHA256; // HMAC mit SHA-256 $algorithm = SigningAlgorithm::HMAC_SHA512; // HMAC mit SHA-512 $algorithm = SigningAlgorithm::RSA_SHA256; // RSA mit SHA-256 $algorithm = SigningAlgorithm::RSA_SHA512; // RSA mit SHA-512 ``` ### RequestSigner Die `RequestSigner`-Klasse ist für das Signieren von ausgehenden Anfragen verantwortlich: ```php use App\Framework\Security\RequestSigning\RequestSigner; // Signer initialisieren $signer = new RequestSigner($clock); // Anfrage signieren $signedRequest = $signer->signRequest( $request, $signingKey, ['(request-target)', 'host', 'date', 'content-type'], 300 // Gültigkeitsdauer in Sekunden ); ``` ### RequestVerifier Die `RequestVerifier`-Klasse ist für die Überprüfung von eingehenden Anfragen verantwortlich: ```php use App\Framework\Security\RequestSigning\RequestVerifier; // Verifier initialisieren $verifier = new RequestVerifier($keyRepository, $clock); // Anfrage verifizieren $result = $verifier->verify($request); if ($result->isSuccess()) { // Anfrage ist gültig $signature = $result->signature; $key = $result->key; } else { // Anfrage ist ungültig $errorMessage = $result->errorMessage; } ``` ### SigningKeyRepository Das `SigningKeyRepository`-Interface definiert die Methoden zum Speichern und Abrufen von Signaturschlüsseln: ```php use App\Framework\Security\RequestSigning\SigningKeyRepository; use App\Framework\Security\RequestSigning\InMemorySigningKeyRepository; use App\Framework\Security\RequestSigning\EntityManagerSigningKeyRepository; // In-Memory-Repository für Tests $repository = new InMemorySigningKeyRepository(); // Entity-Manager-Repository für Produktion $repository = new EntityManagerSigningKeyRepository($entityManager); // Schlüssel speichern $repository->store($signingKey); // Schlüssel abrufen $key = $repository->findByKeyId('api-key-1'); // Alle aktiven Schlüssel abrufen $activeKeys = $repository->getAllActive(); // Schlüssel entfernen $repository->remove('api-key-1'); // Schlüssel rotieren $repository->rotateKey('api-key-1', $newKey); ``` ## Signaturformat Das Framework verwendet das [HTTP Signature](https://tools.ietf.org/html/draft-cavage-http-signatures) Format für Request Signing: ``` Authorization: Signature keyId="api-key-1",algorithm="hmac-sha256",headers="(request-target) host date",signature="Base64(HMAC-SHA256(SigningString))" ``` Die Signatur wird aus einer Zeichenkette (Signing String) generiert, die aus den angegebenen Header-Werten besteht: ``` (request-target): post /api/data host: example.com date: Tue, 07 Jun 2023 20:51:35 GMT ``` ## Verwendung ### Ausgehende Anfragen signieren ```php // In einem API-Client public function sendRequest(HttpRequest $request): HttpResponse { // Anfrage signieren $signedRequest = $this->requestSigningService->signOutgoingRequest( $request, 'api-key-1', // Optional: Spezifischer Schlüssel ['(request-target)', 'host', 'date', 'content-type'], // Optional: Zu signierende Header 300 // Optional: Gültigkeitsdauer in Sekunden ); // Signierte Anfrage senden return $this->httpClient->send($signedRequest); } ``` ### Eingehende Anfragen verifizieren ```php // In einer Middleware public function __invoke(MiddlewareContext $context, Next $next): MiddlewareContext { $request = $context->request; // Prüfen, ob die Route signierte Anfragen erfordert if ($this->requiresSignature($request->path)) { $result = $this->requestSigningService->verifyIncomingRequest($request); if (!$result->isSuccess()) { return $context->withResponse( new Response(401, [], ['error' => 'Ungültige Signatur: ' . $result->errorMessage]) ); } } return $next($context); } ``` ### Schlüsselverwaltung ```php // HMAC-Schlüssel generieren $key = $requestSigningService->generateHmacKey( 'api-key-1', SigningAlgorithm::HMAC_SHA256, new \DateTimeImmutable('+30 days') ); // RSA-Schlüssel erstellen $privateKey = file_get_contents('private_key.pem'); $key = $requestSigningService->createRsaKey( 'api-key-2', $privateKey, new \DateTimeImmutable('+1 year') ); // Schlüssel rotieren $newKey = SigningKey::generateHmac('api-key-1-new', SigningAlgorithm::HMAC_SHA256); $requestSigningService->rotateSigningKey('api-key-1', $newKey); // Schlüssel entfernen $requestSigningService->removeSigningKey('api-key-1'); // Alle aktiven Schlüssel abrufen $activeKeys = $requestSigningService->getActiveKeys(); ``` ## Integration mit dem Framework ### RequestSigningMiddleware Das Framework bietet eine `RequestSigningMiddleware`, die automatisch eingehende Anfragen verifiziert: ```php // In der Bootstrap-Datei oder Router-Konfiguration $app->addMiddleware(RequestSigningMiddleware::class); ``` ### HttpClientSigningMiddleware Für ausgehende Anfragen bietet das Framework eine `HttpClientSigningMiddleware`: ```php // HTTP-Client mit Signatur-Middleware konfigurieren $httpClient = new HttpClient([ 'middlewares' => [ new HttpClientSigningMiddleware($requestSigningService) ] ]); // Anfragen werden automatisch signiert $response = $httpClient->send($request); ``` ### Konfiguration Die Request-Signing-Funktionen können in der Konfigurationsdatei angepasst werden: ```php // config/security.php return [ 'request_signing' => [ 'enabled' => true, 'default_algorithm' => 'hmac-sha256', 'default_headers' => ['(request-target)', 'host', 'date', 'content-type'], 'default_expiry' => 300, // Sekunden 'required_routes' => [ '/api/admin/*', '/api/payments/*', ], ], ]; ``` ## Erweiterte Funktionen ### Signatur mit Ablaufdatum Signaturen können mit einem Ablaufdatum versehen werden, um Replay-Angriffe zu verhindern: ```php // Anfrage mit Ablaufdatum signieren $signedRequest = $requestSigningService->signOutgoingRequest( $request, 'api-key-1', ['(request-target)', 'host', 'date', '(created)', '(expires)'], 300 // Gültigkeitsdauer in Sekunden ); ``` Die Signatur enthält dann zusätzliche Felder: ``` Authorization: Signature keyId="api-key-1",algorithm="hmac-sha256",headers="(request-target) host date (created) (expires)",created=1623094295,expires=1623094595,signature="..." ``` ### Digest-Header Für zusätzliche Sicherheit kann der Anfrage-Body mit einem Digest-Header geschützt werden: ```php // Anfrage mit Digest-Header signieren $request = $request->withHeader('Digest', 'SHA-256=' . base64_encode(hash('sha256', $request->body, true))); $signedRequest = $requestSigningService->signOutgoingRequest( $request, 'api-key-1', ['(request-target)', 'host', 'date', 'digest'] ); ``` ### Schlüsselrotation Für zusätzliche Sicherheit sollten Schlüssel regelmäßig rotiert werden: ```php // Neuen Schlüssel generieren $newKey = $requestSigningService->generateHmacKey( 'api-key-1-new', SigningAlgorithm::HMAC_SHA256 ); // Alten Schlüssel durch neuen ersetzen $requestSigningService->rotateSigningKey('api-key-1', $newKey); // Alten Schlüssel nach einer Übergangszeit entfernen // (nachdem alle Clients auf den neuen Schlüssel umgestellt wurden) $requestSigningService->removeSigningKey('api-key-1'); ``` ## Sicherheitsüberlegungen ### Best Practices 1. **Verwenden Sie starke Algorithmen**: HMAC-SHA256 oder RSA-SHA256 sind empfohlen. 2. **Schützen Sie private Schlüssel**: Speichern Sie private Schlüssel sicher und teilen Sie sie nie öffentlich. 3. **Signieren Sie kritische Header**: Mindestens `(request-target)`, `host`, `date` und `content-type` sollten signiert werden. 4. **Verwenden Sie Ablaufdaten**: Sowohl für Schlüssel als auch für Signaturen, um Replay-Angriffe zu verhindern. 5. **Rotieren Sie Schlüssel regelmäßig**: Implementieren Sie einen Prozess zur regelmäßigen Schlüsselrotation. ### Bekannte Einschränkungen - Request Signing schützt nicht vor Man-in-the-Middle-Angriffen; verwenden Sie immer HTTPS. - Die Sicherheit hängt von der sicheren Speicherung und Verteilung der Schlüssel ab. - Uhrzeitsynchronisation zwischen Client und Server ist wichtig für zeitbasierte Validierung. ## Fehlerbehebung ### Häufige Probleme #### Signaturvalidierung schlägt fehl Mögliche Ursachen: - Die Signatur ist abgelaufen - Die Uhrzeit zwischen Client und Server ist nicht synchronisiert - Der falsche Schlüssel wird verwendet - Die Header-Liste stimmt nicht überein - Der Anfrage-Body wurde nach der Signierung geändert Lösung: - Überprüfen Sie die Uhrzeit auf Client und Server - Stellen Sie sicher, dass der richtige Schlüssel verwendet wird - Überprüfen Sie, ob alle erforderlichen Header signiert werden - Verwenden Sie den Digest-Header für Anfragen mit Body #### Schlüssel nicht gefunden Wenn der Schlüssel nicht gefunden wird: ```php // Prüfen, ob der Schlüssel existiert $key = $keyRepository->findByKeyId($keyId); if ($key === null) { // Schlüssel nicht gefunden $this->logger->warning('Signing key not found', ['key_id' => $keyId]); } ``` #### Logging für Fehlerbehebung Das Framework bietet umfangreiches Logging für Request Signing: ```php // In der RequestSigningService-Klasse $this->logger->info('Request signature verified successfully', [ 'key_id' => $result->signature->keyId, 'algorithm' => $result->signature->algorithm->value, 'path' => $request->path, ]); $this->logger->warning('Request signature verification failed', [ 'error' => $result->errorMessage, 'path' => $request->path, ]); ``` ## Weiterführende Informationen - [Security Features Übersicht](index.md) - [CSRF-Schutz](csrf-protection.md) - [Security Headers](security-headers.md) - [Sicherheits-Best-Practices](/guides/security-best-practices.md) - [HTTP Signatures Spezifikation](https://tools.ietf.org/html/draft-cavage-http-signatures)