Übersicht
Status- und Kennzahlen des Lizenzsystems auf einen Blick.
0
Gesamte Lizenzen
0
Aktive Lizenzen
0
Abgelaufene Lizenzen
0
Gesperrte / Inaktive
0
Verifizierungen (24h)
Letzte Verifizierungs-Aktivitäten
| Lizenzschlüssel | Client-IP | Domain | Ergebnis | Zeitstempel |
|---|
Lizenzverwaltung
Kundenlizenzen erstellen, konfigurieren, sperren und freischalten.
Modul-Definitionen
Definieren Sie Berechtigungsfelder und Limits, die in Lizenzen freigeschaltet werden können.
Audit & Verifizierungs-Logs
Vollständiges Protokoll aller API-Abfragen von Client-Installationen.
API-Verifizierungs-Tester
Testen Sie die Verifizierungs-API direkt im Browser wie eine echte Kunden-Installation.
Anfrage konfigurieren (POST /api/v1/licenses/verify)
Server-Antwort (JSON)
// Klicken Sie auf "Verifikation simulieren" um die API-Antwort zu sehen...
Einstellungen & Sicherheit
Konfiguration und Server-Sicherheitsstatus verwalten.
Admin-Passwort ändern
Server-Informationen
node:sqlite)scrypt mit 16-Byte kryptografischem SaltPOST /api/v1/licenses/verifyHilfe & Entwickler-Dokumentation
Systemarchitektur, Verifikations-Lebenszyklus, API-Referenz mit Live-Codebeispielen und Sicherheitsrichtlinien.
Funktionsweise des Lizenzsystems
Architecture & LifecycleDer Lizenz-Server dient als zentrale Authentifizierungs- und Entitlement-Instanz für Ihre Security Awareness Plattform (TrainSec).
1. Lizenzausstellung & Modul-Definition
Administratoren erstellen Lizenzen mit Schlüssel (z.B. SEC-XXXX-XXXX), optionalem Ablaufdatum, Kundenbindung und dynamischen Modul-Berechtigungen (z.B. Phishing-Simulation, KI-Coach, User-Limits).
2. Client-Initialisierung & Handshake
Beim Starten oder periodisch (z.B. 1x täglich per Cronjob) sendet die Awareness-Plattform einen POST-Request mit Lizenzschlüssel, eigener Domain und Instanz-ID an /api/v1/licenses/verify.
3. Validierung & Auto-Binding
Der Server prüft Existenz, Status (aktiv/gesperrt/abgelaufen) und Bindung. Ist 'Auto-Lock' aktiv, bindet sich die Lizenz bei der Erstabfrage dauerhaft an Domain und Hardware-ID des Kunden.
4. Signierte Antwort (HMAC-SHA256)
Die Antwort enthält alle freigeschalteten Module und Limits sowie eine kryptografische Signatur. Der Client validiert die Signatur mit dem gemeinsamen Secret vor Freischaltung der Features.
5. Lückenloser Audit-Trail
Jede einzelne Verifikation wird manipulationssicher mit Timestamp, Client-IP, angefragter Domain, Instanz-ID und Prüfergebnis in der Datenbank protokolliert.
🧩 Dynamische Module (Entitlements)
Statt starrer Editionen werden Module (Booleans, Zahlenlimits, Texte) zentral im Admin-Panel definiert und dynamisch übermittelt. Der Client liest z.B. response.modules.phishing_simulation oder response.modules.max_users aus.
🔒 Domain-Bindung & Wildcards
Lizenzen können auf exakte Domains (awareness.kunde.de) oder Wildcard-Domains (*.kunde.de) beschränkt werden. Bei Abweichungen antwortet der Server mit HTTP 403 (domain_mismatch).
⏳ Status- & Laufzeit-Management
Status active, suspended (temporär pausiert) oder revoked (widerrufen). Sobald das expires_at Datum überschritten ist, wechselt der Status automatisch zu expired.
API-Referenz & Beispielabfragen
POST /api/v1/licenses/verifyVerwenden Sie den Verifikations-Endpoint direkt in Ihrer Anwendung. Wählen Sie Ihre Programmiersprache:
# Lizenz-Verifikation via cURL im Terminal (HTTPS ohne Portnummer)
curl -X POST "https:///api/v1/licenses/verify" \
-H "Content-Type: application/json" \
-d '{
"license_key": "SEC-ABCD-1234-EFGH-5678",
"domain": "awareness.kunde.de",
"instance_id": "server-node-01",
"system_version": "2.4.0"
}'
import crypto from 'node:crypto';
// Shared Secret aus .env des Client-Backends
const SIGNING_SECRET = process.env.LICENSE_SIGNING_SECRET || 'geheimes-shared-secret';
// Deployment-URL des Lizenz-Servers (HTTPS ohne Portnummer)
const LICENSE_SERVER_URL = process.env.LICENSE_SERVER_URL || 'https://';
/**
* Überprüft den Lizenzschlüssel und validiert die kryptografische HMAC-Signatur
*/
async function verifyLicense(licenseKey, domain, instanceId) {
const response = await fetch(`${LICENSE_SERVER_URL}/api/v1/licenses/verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
license_key: licenseKey,
domain: domain,
instance_id: instanceId,
system_version: '2.4.0'
})
});
const data = await response.json();
if (!response.ok || !data.valid) {
throw new Error(`Lizenzprüfung fehlgeschlagen: ${data.error || data.status}`);
}
// 1. Signaturprüfung (HMAC-SHA256 mit alphabetisch sortierten JSON-Keys)
const { signature, ...payloadToVerify } = data;
const normalized = JSON.stringify(payloadToVerify, Object.keys(payloadToVerify).sort());
const expectedSignature = crypto
.createHmac('sha256', SIGNING_SECRET)
.update(normalized)
.digest('hex');
const bufReceived = Buffer.from(signature, 'hex');
const bufExpected = Buffer.from(expectedSignature, 'hex');
if (bufReceived.length !== bufExpected.length || !crypto.timingSafeEqual(bufReceived, bufExpected)) {
throw new Error('Sicherheitsalarm: Ungültige HMAC-Signatur! Daten wurden manipuliert.');
}
// 2. Replay-Schutz: Zeitstempel überprüfen (max. 5 Minuten Abweichung)
const responseTime = new Date(data.timestamp).getTime();
if (Math.abs(Date.now() - responseTime) > 5 * 60 * 1000) {
throw new Error('Replay-Angriff erkannt: Zeitstempel der Serverantwort ist abgelaufen!');
}
console.log(`✅ Lizenz aktiv für: ${data.customer} (Ablauf: ${data.expires_at || 'Unbegrenzt'})`);
console.log('Freigeschaltete Module:', data.modules);
return data;
}
import hmac
import hashlib
import json
import os
import requests
from datetime import datetime, timezone
SIGNING_SECRET = os.getenv("LICENSE_SIGNING_SECRET", "geheimes-shared-secret")
# Deployment-URL des Lizenz-Servers (HTTPS ohne Portnummer)
SERVER_URL = os.getenv("LICENSE_SERVER_URL", "https://")
def verify_license(license_key, domain="awareness.kunde.de", instance_id="server-node-01"):
url = f"{SERVER_URL}/api/v1/licenses/verify"
payload = {
"license_key": license_key,
"domain": domain,
"instance_id": instance_id,
"system_version": "2.4.0"
}
resp = requests.post(url, json=payload, timeout=10)
data = resp.json()
if resp.status_code != 200 or not data.get("valid"):
raise PermissionError(f"Lizenz ungültig: {data.get('error', data.get('status'))}")
# Signatur aus Antwort trennen
server_sig = data.pop("signature", "")
# Payload mit sortierten Schlüsseln normalisieren
normalized = json.dumps(data, sort_keys=True, separators=(',', ':'))
expected_sig = hmac.new(
SIGNING_SECRET.encode('utf-8'),
normalized.encode('utf-8'),
hashlib.sha256
).hexdigest()
# Constant-Time Signaturvergleich
if not hmac.compare_digest(server_sig, expected_sig):
raise SecurityError("Kryptografische Signatur ungültig! Daten wurden möglicherweise abgefangen.")
print(f"✅ Lizenz bestätigt für Kunde: {data.get('customer')}")
print(f"Modul-Berechtigungen: {data.get('modules')}")
return data
';
$payload = json_encode([
'license_key' => 'SEC-ABCD-1234-EFGH-5678',
'domain' => 'awareness.kunde.de',
'instance_id' => 'server-node-01',
'system_version' => '2.4.0'
]);
$ch = curl_init("$serverUrl/api/v1/licenses/verify");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$rawResponse = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($rawResponse, true);
if ($httpCode !== 200 || empty($data['valid'])) {
throw new Exception("Lizenz ungültig: " . ($data['error'] ?? 'HTTP ' . $httpCode));
}
// Signaturprüfung
$receivedSig = $data['signature'] ?? '';
unset($data['signature']);
// Normalisierung: Alphabetische Sortierung der Schlüssel
ksort($data);
$normalized = json_encode($data, JSON_UNESCAPED_SLASHES);
$expectedSig = hash_hmac('sha256', $normalized, $signingSecret);
if (!hash_equals($receivedSig, $expectedSig)) {
throw new SecurityException("Kritischer Fehler: HMAC-Signatur stimmt nicht überein!");
}
echo "✅ Lizenz verifiziert für: " . htmlspecialchars($data['customer']) . "\n";
print_r($data['modules']);
?>
Request-Payload (JSON)
{
"license_key": "SEC-XXXX-XXXX-XXXX-XXXX", // Pflicht
"domain": "awareness.kunde.de", // Empfohlen
"instance_id": "server-node-01", // Optional (Hardware-ID)
"system_version": "2.4.0" // Optional (Version)
}
Erfolgreiche Server-Antwort (HTTP 200)
{
"valid": true,
"status": "active",
"customer": "Musterfirma GmbH",
"license_key": "SEC-XXXX-XXXX-XXXX-XXXX",
"expires_at": "2027-12-31T23:59:59.000Z",
"days_remaining": 480,
"bound_domain": "awareness.kunde.de",
"bound_instance_id": "server-node-01",
"modules": {
"phishing_simulation": true,
"max_users": 500
},
"custom_fields": { "sla_tier": "gold" },
"timestamp": "2026-09-07T15:00:00.000Z",
"signature": "8f3b2a9c1..."
}
Sicherheitsrichtlinien für Client-Entwickler
Security Best PracticesVerbindliche Richtlinien zur sicheren Implementierung der Lizenzprüfung auf Client-Seite:
1. Kryptografische Signaturprüfung im Client (Pflicht)
MandatoryAkzeptieren Sie niemals blind HTTP 200 oder valid: true! Durch DNS-Spoofing, Reverse-Proxies oder manipulierte Hosts-Dateien könnte ein Angreifer Antworten fälschen. Berechnen Sie im Client stets die HMAC-SHA256 Signatur der normalisierten Payload (alphabetisch sortierte JSON-Keys) und vergleichen Sie diese mittels Constant-Time-Vergleich (timingSafeEqual).
2. Offline-Grace-Period & Caching-Strategie
EmpfohlenFragen Sie die Lizenz nicht bei jedem Webseiten-Aufruf ab! Cachen Sie das letzte gültige, verifizierte Ergebnis in der lokalen Datenbank. Gewähren Sie eine Offline-Kulanzzeit (Grace Period) von 3 bis 7 Tagen bei Ausfall der Netzwerkverbindung, um Produktionsausfälle beim Kunden zu verhindern.
3. Replay-Schutz durch Zeitstempel-Validierung
EmpfohlenPrüfen Sie im Client das Feld 'timestamp' in der Server-Antwort. Weicht der Zeitstempel um mehr als 5 Minuten von der Client-Systemzeit ab, sollte die Antwort verworfen werden, um Replay-Angriffe mit alten abgefangenen Signaturen zu unterbinden.
4. Schutz des Signaturschlüssels (Shared Secret)
Best PracticeDer LICENSE_SIGNING_SECRET darf niemals im Frontend (Browser/JavaScript) oder in öffentlichen Git-Repositories liegen. Speichern Sie das Secret ausschließlich in Server-Umgebungsvariablen (.env) mit strikten Lese-Rechten.
5. Domain- & Hardware-Locks (Anti-Piracy)
Best PracticeAktivieren Sie bei der Lizenzausstellung 'Automatisch binden' oder tragen Sie die Kunden-Domain (z.B. awareness.firma.de oder Wildcard *.firma.de) ein. Dies verhindert, dass derselbe Lizenzschlüssel auf unberechtigten Fremdservern verwendet wird.
6. DoS-Vermeidung & Rate-Limits
WichtigDer Lizenz-Server schützt sich mit einem Rate-Limiter (max. 60 Anfragen/Minute pro IP). Wiederholte Fehlversuche werden temporär geblockt. Nutzen Sie exponentielles Backoff bei Verbindungsproblemen.