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
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,410 @@
# 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)