Schluessel sicher ausgeben, rotieren und im Ernstfall widerrufen
API-Keys oeffnen Schnittstellen fuer Partner, Marketplaces und interne Services, doch unsachgemaess verwaltete Schluessel gehoeren zu den haeufigsten Einfallstoren fuer Datenlecks. Dieser Artikel zeigt, wie ihr API-Keys mit ausreichender Entropie erzeugt, auf minimale Berechtigungen beschraenkt, ohne Ausfallzeit rotiert und bei Verdacht auf Kompromittierung sofort widerruft, praxisnah fuer Magento-Backends.
Inhaltsverzeichnis
- 1. API-Key vs. OAuth-Token: Wann welches Verfahren
- 2. Sichere Schluesselerzeugung: ausreichende Entropie
- 3. Scoping: Berechtigungen auf das Minimum beschraenken
- 4. Rotationsstrategie ohne Downtime
- 5. Sofortiger Widerruf bei Kompromittierung
- 6. Niemals im Client-Code oder in URLs exponieren
- 7. Speicherung und Secrets-Management
- 8. Rate Limiting und Monitoring der Key-Nutzung
- 9. Magento-spezifische Implementierung: eigenes API-Key-Modul
- 10. Zusammenfassung
- 11. FAQ
1. API-Key vs. OAuth-Token: Wann welches Verfahren
Ein API-Key ist ein einzelnes, langlebiges Geheimnis, das ein Client bei jeder Anfrage mitschickt, meist ohne eingebauten Ablaufmechanismus oder differenzierte Berechtigungslogik. OAuth 2.0 hingegen trennt Identitaet, Autorisierung und Zugriffstoken in mehrere Rollen: Client Credentials, Access Token und Refresh Token, mit klar definierter Lebensdauer und Scope pro Token. Fuer Server-zu-Server-Integrationen ohne Nutzerkontext, etwa den Abgleich von Bestandsdaten zwischen Magento und einem ERP-System, ist ein API-Key oft die pragmatischere Wahl, weil kein Autorisierungsserver, kein Token-Refresh-Flow und keine zusaetzliche Infrastruktur noetig sind.
Der Nachteil zeigt sich bei der Skalierung: Ohne Ablaufdatum bleibt ein einmal ausgestellter API-Key faktisch fuer immer gueltig, bis er manuell widerrufen wird. OAuth-Tokens laufen dagegen automatisch ab und zwingen Clients zu einem Refresh-Zyklus, der Kompromittierungen von selbst begrenzt. Wer viele externe Partner mit unterschiedlichen Berechtigungsstufen anbindet oder delegierten Zugriff im Namen eines Nutzers benoetigt, kommt an OAuth kaum vorbei. Fuer interne, klar abgegrenzte Integrationen mit wenigen Systemen bleibt der API-Key wegen seiner Einfachheit die richtige Wahl, solange Rotation und Scoping konsequent umgesetzt werden.
2. Sichere Schluesselerzeugung: ausreichende Entropie
Die Sicherheit eines API-Keys haengt fast ausschliesslich von seiner Entropie ab, also der Anzahl zufaelliger Bits, die ein Angreifer erraten muesste. Ein Key, der aus uniqid(), einem Zeitstempel oder einer inkrementellen ID abgeleitet wird, ist vorhersagbar und damit wertlos als Geheimnis, selbst wenn er lang aussieht. Kryptografisch sichere Zufallsgeneratoren wie random_bytes() in PHP oder sodium_crypto_secretbox_keygen() liefern echte Zufallswerte aus dem Betriebssystem-Entropie-Pool und sind die einzig akzeptable Grundlage fuer Schluesselerzeugung.
Als Faustregel gelten mindestens 256 Bit Entropie, also 32 zufaellige Bytes, die anschliessend base64- oder hex-kodiert werden, um sie sicher in URLs, Headern und Konfigurationsdateien zu transportieren. Ein zusaetzliches Praefix wie msft_live_ oder msft_test_ erleichtert das Erkennen von versehentlich committeten Keys durch automatisierte Secret-Scanner in der CI-Pipeline, ohne die Entropie des eigentlichen Geheimnisses zu verringern. Wichtig ist, den generierten Klartext-Key dem Nutzer genau einmal beim Erstellen anzuzeigen und serverseitig nur einen Hash zu speichern, damit ein Datenbank-Leak nicht automatisch alle aktiven Keys kompromittiert.
<?php
declare(strict_types=1);
namespace Mironsoft\ApiKeyManager\Service;
/**
* Generates cryptographically secure API keys and their storage hash.
*/
final class ApiKeyGenerator
{
private const PREFIX_LIVE = 'msft_live_';
private const KEY_BYTES = 32; // 256 bit entropy
/**
* Generate a new plaintext API key and its hash for persistence.
*
* @return array{plain: string, hash: string, prefix: string}
*/
public function generate(): array
{
// Cryptographically secure random bytes, never uniqid() or time()-based values
$randomBytes = random_bytes(self::KEY_BYTES);
$secret = rtrim(strtr(base64_encode($randomBytes), '+/', '-_'), '=');
$plain = self::PREFIX_LIVE . $secret;
// Store only the hash, plaintext is shown to the user exactly once
$hash = hash('sha256', $plain);
// Short prefix for support/log identification without revealing the secret
$prefix = substr($plain, 0, strlen(self::PREFIX_LIVE) + 8);
return ['plain' => $plain, 'hash' => $hash, 'prefix' => $prefix];
}
/**
* Verify a supplied plaintext key against a stored hash using constant-time comparison.
*
* @param string $plain
* @param string $storedHash
* @return bool
*/
public function verify(string $plain, string $storedHash): bool
{
return hash_equals($storedHash, hash('sha256', $plain));
}
}
3. Scoping: Berechtigungen auf das Minimum beschraenken
Ein API-Key ohne Scope ist ein Generalschluessel: Wird er kompromittiert, hat ein Angreifer sofort vollen Zugriff auf alle Endpunkte und Daten. Scoping bindet einen Key stattdessen an eine minimale Menge erlaubter Aktionen, etwa nur lesenden Zugriff auf Produktbestaende oder ausschliesslich das Anlegen neuer Bestellungen, niemals aber Zugriff auf Kundendaten oder Zahlungsinformationen. Das Prinzip der geringsten Rechte reduziert den Schaden im Kompromittierungsfall auf genau den Bereich, fuer den der Key ausgestellt wurde.
In der Praxis modelliert man Scopes als benannte Berechtigungen, etwa catalog:read, orders:write oder customers:none, die bei der Ausstellung eines Keys explizit zugewiesen werden und bei jeder Anfrage serverseitig geprueft werden, nie nur clientseitig. Granularitaet ist ein Kompromiss: Zu feine Scopes erzeugen Verwaltungsaufwand, zu grobe Scopes untergraben das Prinzip der geringsten Rechte. Eine bewaehrte Struktur orientiert sich an Ressource und Aktion, kombiniert mit einer klaren Trennung zwischen Lese- und Schreibzugriff sowie separaten Scopes fuer sensible Bereiche wie Zahlungsdaten oder Admin-Funktionen.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="mironsoft_apikeymanager" translate="label" type="text" sortOrder="200" showInDefault="1" showInWebsite="0" showInStore="0">
<label>API Key Management</label>
<tab>mironsoft</tab>
<resource>Mironsoft_ApiKeyManager::config</resource>
<group id="rotation" translate="label" sortOrder="10" showInDefault="1">
<label>Rotation</label>
<field id="default_ttl_days" translate="label" type="text" sortOrder="10" showInDefault="1">
<label>Default Key Lifetime (days)</label>
<validate>validate-number validate-greater-than-zero</validate>
</field>
<field id="overlap_window_days" translate="label" type="text" sortOrder="20" showInDefault="1">
<label>Rotation Overlap Window (days)</label>
<comment>Old key stays valid this many days after a new key is issued.</comment>
</field>
</group>
<group id="scopes" translate="label" sortOrder="20" showInDefault="1">
<label>Available Scopes</label>
<field id="allowed_scopes" translate="label" type="textarea" sortOrder="10" showInDefault="1">
<label>Allowed Scopes (one per line)</label>
<comment>e.g. catalog:read, orders:write, customers:none</comment>
</field>
</group>
</section>
</system>
</config>
4. Rotationsstrategie ohne Downtime
Regelmaessige Rotation begrenzt das Zeitfenster, in dem ein gestohlener Key nutzbar bleibt, selbst wenn der Diebstahl unbemerkt bleibt. Der groesste praktische Fehler bei der Rotation ist, den alten Key sofort beim Ausstellen des neuen zu deaktivieren: Jeder Client, der den neuen Key noch nicht eingespielt hat, verliert augenblicklich den Zugriff, was in verteilten Systemen mit mehreren Deployment-Zyklen fast garantiert zu Ausfaellen fuehrt.
Die robuste Loesung ist ein Ueberlappungsfenster: Ein neuer Key wird erzeugt, waehrend der alte parallel fuer einen definierten Zeitraum, etwa 7 bis 14 Tage, gueltig bleibt. Beide Keys funktionieren waehrenddessen gleichzeitig, sodass Clients ihre Konfiguration ohne Zeitdruck aktualisieren koennen. Nach Ablauf des Ueberlappungsfensters wird der alte Key automatisch deaktiviert, idealerweise durch einen geplanten Cronjob statt durch manuelles Eingreifen. Fuer hochsensible Integrationen empfiehlt sich ein festes Rotationsintervall von 90 Tagen, ergaenzt um sofortige Ad-hoc-Rotation bei jedem Verdacht auf Kompromittierung.
#!/usr/bin/env bash
# rotate-api-key.sh - Issue a new API key with an overlap window, no downtime
set -euo pipefail
CLIENT_ID="${1:?Usage: rotate-api-key.sh <client_id>}"
OVERLAP_DAYS="${OVERLAP_DAYS:-10}"
echo "[INFO] Issuing new key for client ${CLIENT_ID}"
NEW_KEY_JSON=$(bin/magento mironsoft:apikey:issue --client-id="${CLIENT_ID}" --scope="catalog:read,orders:write" --format=json)
NEW_PREFIX=$(echo "${NEW_KEY_JSON}" | jq -r '.prefix')
echo "[INFO] New key issued with prefix ${NEW_PREFIX}"
echo "[INFO] Old key(s) remain valid for ${OVERLAP_DAYS} more days"
# Schedule the old key deactivation instead of an immediate hard cutover
bin/magento mironsoft:apikey:schedule-deactivation --client-id="${CLIENT_ID}" --exclude-prefix="${NEW_PREFIX}" --after-days="${OVERLAP_DAYS}"
echo "[INFO] Notify integration partner about the new key and the overlap deadline"
echo "[OK] Rotation initiated. Old and new keys are active in parallel."
5. Sofortiger Widerruf bei Kompromittierung
Ein Widerruf muss sofort wirksam werden, ohne auf den naechsten Cache-Refresh, Deployment oder Neustart zu warten. Das setzt voraus, dass die Gueltigkeitspruefung eines Keys nicht ausschliesslich aus einem langlebigen Application-Cache gelesen wird, sondern bei jeder Anfrage, oder zumindest mit sehr kurzer Cache-TTL von wenigen Sekunden, gegen die aktuelle Datenbank oder einen zentralen Revocation-Store geprueft wird.
Ein praktikables Muster ist eine Sperrliste in Redis mit dem gehashten Key als Schluessel und einer kurzen TTL, die parallel zur Datenbank geprueft wird und damit auch bei verteilten Applikationsservern konsistent sofort greift. Jeder Widerruf sollte protokolliert werden, mit Zeitpunkt, ausloesendem Nutzer und Grund, um im Nachhinein nachvollziehen zu koennen, ob die Kompromittierung bereits vorher zu ungewoehnlichem Traffic gefuehrt hat. Fuer den Ernstfall lohnt sich ein vorbereitetes Runbook, das den Widerruf, die Benachrichtigung betroffener Teams und die Ausstellung eines Ersatz-Keys in einem einzigen dokumentierten Ablauf beschreibt, statt die Reaktion unter Stress zu improvisieren.
#!/usr/bin/env bash
# revoke-api-key.sh - Immediately revoke a compromised API key
set -euo pipefail
KEY_PREFIX="${1:?Usage: revoke-api-key.sh <key_prefix> <reason>}"
REASON="${2:?Usage: revoke-api-key.sh <key_prefix> <reason>}"
echo "[ALERT] Revoking key with prefix ${KEY_PREFIX}"
bin/magento mironsoft:apikey:revoke --prefix="${KEY_PREFIX}" --reason="${REASON}"
# Purge any short-lived validation cache so revocation is effective within seconds
bin/cache-clean mironsoft_apikey_validation
echo "[INFO] Revocation logged. Notifying security channel."
bin/magento mironsoft:apikey:notify-revocation --prefix="${KEY_PREFIX}" --reason="${REASON}"
echo "[OK] Key ${KEY_PREFIX} revoked and integration team notified."
6. Niemals im Client-Code oder in URLs exponieren
Ein API-Key, der im clientseitigen JavaScript, in einer mobilen App oder in einer oeffentlich zugaenglichen Konfigurationsdatei liegt, ist kein Geheimnis mehr, sobald ein Nutzer die Developer-Tools oeffnet oder die App dekompiliert. Secrets gehoeren ausschliesslich in serverseitigen Code, in Umgebungsvariablen oder einen dedizierten Secrets-Manager, niemals in Frontend-Bundles, Mobile-App-Binaries oder oeffentliche Git-Repositories. Wer clientseitig ueberhaupt eine Autorisierung braucht, sollte kurzlebige, eng gescopte Tokens ausstellen, die ein Backend-Proxy im Namen des Clients anfordert, statt den eigentlichen API-Key preiszugeben.
Genauso kritisch ist die Uebertragung: Ein Key in der URL-Query-String, etwa ?api_key=xyz, landet zuverlaessig in Server-Access-Logs, Browser-History, Proxy-Logs und Referrer-Headern Dritter, selbst wenn die Verbindung per TLS verschluesselt ist. Der korrekte Transportweg ist der Authorization-Header mit dem Schema Bearer oder einem eigenen Praefix, da Header standardmaessig nicht in Access-Logs landen und nicht ueber Referrer weitergereicht werden. Zusaetzlich sollten Access-Logs so konfiguriert werden, dass Header-Werte grundsaetzlich nicht mitgeloggt werden, um versehentliche Leaks ueber die Logging-Infrastruktur selbst auszuschliessen.
<?php
declare(strict_types=1);
namespace Mironsoft\ApiKeyManager\Plugin;
use Magento\Framework\Webapi\Rest\Request;
use Magento\Framework\Exception\AuthorizationException;
use Mironsoft\ApiKeyManager\Api\ApiKeyRepositoryInterface;
/**
* Validates the API key and its scope before a REST request reaches the controller.
*/
final class ValidateApiKeyPlugin
{
/**
* @param ApiKeyRepositoryInterface $apiKeyRepository
*/
public function __construct(
private readonly ApiKeyRepositoryInterface $apiKeyRepository
) {
}
/**
* Check key validity, expiry, revocation status and required scope.
*
* @param Request $subject
* @param string $requiredScope
* @throws AuthorizationException
* @return void
*/
public function beforeDispatch(Request $subject, string $requiredScope): void
{
$header = $subject->getHeader('Authorization') ?: '';
if (!str_starts_with($header, 'Bearer ')) {
throw new AuthorizationException(__('Missing or malformed Authorization header.'));
}
$plainKey = substr($header, 7);
$apiKey = $this->apiKeyRepository->getByHash(hash('sha256', $plainKey));
if ($apiKey === null || $apiKey->isRevoked() || $apiKey->isExpired()) {
throw new AuthorizationException(__('API key is invalid, expired or revoked.'));
}
if (!in_array($requiredScope, $apiKey->getScopes(), true)) {
throw new AuthorizationException(__('API key is missing required scope: %1', $requiredScope));
}
}
}
7. Speicherung und Secrets-Management
In der Datenbank gehoert niemals der Klartext-Key gespeichert, sondern ausschliesslich ein kryptografischer Hash, analog zur Passwortspeicherung. Da API-Keys bereits selbst hohe Entropie besitzen, reicht ein schneller Hash wie SHA-256 aus, ein aufwendiges Passwort-Hashing-Verfahren wie bcrypt oder Argon2 ist hier nicht noetig und wuerde bei der Validierung jeder einzelnen Anfrage unnoetig Latenz erzeugen. Ein zusaetzlich gespeichertes Praefix der ersten Zeichen erlaubt es, einen Key in Support-Anfragen oder Logs eindeutig zu identifizieren, ohne das Geheimnis selbst preiszugeben.
Fuer die Konfiguration der eigenen Anwendung, etwa Datenbank-Zugangsdaten oder Keys fuer ausgehende Integrationen, sollte niemals eine .env-Datei im Web-Root oder ein Secret im Git-Repository liegen. Dedizierte Secrets-Manager wie HashiCorp Vault, AWS Secrets Manager oder, fuer kleinere Setups, verschluesselte Umgebungsvariablen ueber den Deployment-Prozess bieten Zugriffskontrolle, Audit-Logs und automatische Rotation fuer die eigenen Infrastruktur-Secrets, getrennt von den API-Keys, die man an Dritte ausgibt.
8. Rate Limiting und Monitoring der Key-Nutzung
Jeder ausgestellte API-Key sollte einem individuellen Rate Limit unterliegen, das ueber die Groesse des Kunden oder Anwendungsfalls hinaus auch als Fruehwarnsystem fuer kompromittierte Keys dient: Ein ploetzlicher, untypischer Anstieg der Anfragen eines einzelnen Keys ist eines der zuverlaessigsten Signale fuer Missbrauch, deutlich vor einer manuellen Log-Analyse. Rate Limits pro Key, nicht nur pro IP-Adresse, verhindern zudem, dass ein einzelner fehlerhafter oder kompromittierter Client das gesamte System fuer alle anderen Nutzer beeintraechtigt.
Fuer Monitoring reicht ein einfaches Dashboard mit Anfragen pro Key ueber Zeit haeufig aus, um Anomalien wie ungewoehnliche Uhrzeiten, geografisch unplausible Zugriffsmuster oder eine ploetzliche Haeufung von 403-Antworten wegen fehlender Berechtigungen zu erkennen. Zusaetzlich lohnt sich ein automatisierter Alert, der bei Ueberschreiten eines definierten Schwellwerts ausgeloest wird und das betroffene Team proaktiv informiert, bevor ein Kunde den Missbrauch selbst meldet. Jede Nutzung eines Keys, erfolgreich oder abgelehnt, gehoert mit Zeitstempel, IP-Adresse und aufgerufenem Endpunkt protokolliert, um im Kompromittierungsfall den Schaden exakt eingrenzen zu koennen.
9. Magento-spezifische Implementierung: eigenes API-Key-Modul
In Magento 2 laesst sich API-Key-Management sauber als eigenstaendiges Modul mit eigener Entitaet, Repository und Admin-Grid umsetzen, statt Drittanbieter-Schluessel unstrukturiert in core_config_data abzulegen. Eine eigene Tabelle mit Feldern fuer gehashten Key, Praefix, Scope, Ablaufdatum und Status bildet die Grundlage, verwaltet ueber ein ServiceContract-Interface analog zu Magentos eigenen Repository-Patterns. Die Validierung erfolgt ueber ein Plugin auf der Webapi-Autorisierungsschicht oder einen dedizierten Controller-Plugin fuer REST-Endpunkte ausserhalb der Standard-Webapi.
Fuer die Admin-Oberflaeche bietet sich ein UI-Grid unter einem eigenen Menuepunkt im Konfigurationsbereich an, das Erstellung, Anzeige des Praefixes, Scope-Zuweisung und Widerruf einzelner Keys erlaubt, mit dem vollstaendigen Klartext-Key nur in einem einmaligen Modal direkt nach der Erstellung. Die ACL-Konfiguration in acl.xml stellt sicher, dass nur berechtigte Admin-Nutzer Keys ausstellen oder widerrufen duerfen, waehrend system.xml globale Einstellungen wie Standard-Rotationsintervall und maximale Gueltigkeitsdauer konfigurierbar macht, statt sie hart im Code zu verankern.
| Praxis | Unsicher | Sicher | Warum es zaehlt |
|---|---|---|---|
| Speicherung | Klartext-Key in der Datenbank | SHA-256-Hash mit Praefix | DB-Leak kompromittiert nicht automatisch alle Keys |
| Scope | Voller Zugriff auf alle Endpunkte | Scope auf einzelne Ressourcen/Aktionen | Schaden im Kompromittierungsfall begrenzt |
| Rotation | Key wird nie rotiert | Rotation alle 90 Tage mit Ueberlappung | Zeitfenster fuer gestohlene Keys minimiert |
| Transport | Key als Query-Parameter in der URL | Key im Authorization-Header | Kein Leak ueber Access-Logs, Referrer, Browser-History |
| Gueltigkeit | Kein Ablaufdatum, unbegrenzt gueltig | TTL mit erzwungenem Ablauf | Vergessene Keys verlieren automatisch Gueltigkeit |
Mironsoft
API-Sicherheit, Secrets-Management und Key-Lifecycle fuer Magento-Integrationen
API-Key-Management professionell absichern?
Wir bauen euer API-Key-Management von der sicheren Ausstellung bis zum Notfall-Widerruf, mit Scoping, Rotation ohne Downtime und Monitoring, als sauberes Magento-Modul statt Ad-hoc-Loesung.
Security-Audit
Bestehende Key-Ausgabe, Speicherung und Transportwege pruefen
Modul-Entwicklung
Scoping, Rotation und Widerruf als eigenstaendiges Magento-Modul
Monitoring-Setup
Rate Limits, Logging und Alerts fuer verdaechtige Key-Nutzung
10. Zusammenfassung
Sicheres API-Key-Management steht und faellt mit vier Grundprinzipien: ausreichende Entropie bei der Erzeugung durch kryptografisch sichere Zufallsgeneratoren, Scoping auf die minimal notwendigen Berechtigungen, eine Rotationsstrategie mit Ueberlappungsfenster statt hartem Cutover, und sofortiger Widerruf bei jedem Verdacht auf Kompromittierung. API-Keys sind fuer Server-zu-Server-Integrationen ohne Nutzerkontext oft die pragmatischere Wahl gegenueber OAuth, verlangen aber dieselbe Disziplin bei Speicherung, Transport und Monitoring wie jedes andere Geheimnis.
Wer Keys ausschliesslich gehasht speichert, sie niemals in URLs oder clientseitigem Code exponiert und jede Nutzung mit Rate Limits und Logging ueberwacht, reduziert die Angriffsflaeche drastisch, ohne die Integration fuer legitime Partner zu verkomplizieren. In Magento 2 laesst sich dieses Modell als eigenstaendiges Modul mit klar getrennten Verantwortlichkeiten fuer Ausstellung, Validierung und Widerruf implementieren, vollstaendig ueber ACL und System-Konfiguration steuerbar, statt als Ad-hoc-Loesung in bestehenden Modulen.
API-Key-Management: Ausgabe, Rotation, Widerruf - Das Wichtigste auf einen Blick
Erzeugung
256 Bit Entropie via random_bytes(), niemals uniqid() oder Zeitstempel. Nur Hash speichern, Klartext einmalig anzeigen.
Scoping
Least Privilege pro Key, granular nach Ressource und Aktion, serverseitig bei jeder Anfrage geprueft.
Rotation & Widerruf
Ueberlappungsfenster statt hartem Cutover, sofortiger Widerruf ueber zentrale Sperrliste bei Verdacht.
Transport & Monitoring
Immer Authorization-Header, nie URL. Rate Limits pro Key und Logging als Fruehwarnsystem.