🛡️

Lizenz-Server Login

Bitte melden Sie sich an, um Lizenzen und Berechtigungen zu verwalten.

🛡️

Lizenz-Server

Security Awareness
Übersicht
A
admin

Ü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.

🔍
Kunde Lizenzschlüssel Status Gültig bis Domain-Bindung Module / Limits Aktionen

Modul-Definitionen

Definieren Sie Berechtigungsfelder und Limits, die in Lizenzen freigeschaltet werden können.

Technischer Schlüssel Name (Deutsch) Name (Englisch) Typ Standardwert Aktionen

Audit & Verifizierungs-Logs

Vollständiges Protokoll aller API-Abfragen von Client-Installationen.

🔍
Zeit Lizenzschlüssel Client-IP Domain Status Nachricht

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

Datenbank: SQLite (Native Node 24 node:sqlite)
Passwort-Verschlüsselung: scrypt mit 16-Byte kryptografischem Salt
Response-Signierung: HMAC-SHA256 mit sicherem Serverschlüssel
Brute-Force Schutz: Rate-Limiting auf Verifikation & Login
API-Endpoint: POST /api/v1/licenses/verify

Hilfe & Entwickler-Dokumentation

Systemarchitektur, Verifikations-Lebenszyklus, API-Referenz mit Live-Codebeispielen und Sicherheitsrichtlinien.

🏗️ Funktionsweise ⚡ API-Referenz & Code 🛡️ Sicherheitsrichtlinien

Funktionsweise des Lizenzsystems

Architecture & Lifecycle

Der Lizenz-Server dient als zentrale Authentifizierungs- und Entitlement-Instanz für Ihre Security Awareness Plattform (TrainSec).

1

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

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

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

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

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/verify

Verwenden 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 Practices

Verbindliche Richtlinien zur sicheren Implementierung der Lizenzprüfung auf Client-Seite:

1. Kryptografische Signaturprüfung im Client (Pflicht)

Mandatory

Akzeptieren 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

Empfohlen

Fragen 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

Empfohlen

Prü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 Practice

Der 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 Practice

Aktivieren 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

Wichtig

Der 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.

Neue Lizenz

Neues Modul hinzufügen