Skip to content
← Alle Beiträge
· Delta1 Labs LizenzierungSicherheitTiefenanalyse

Anatomie eines signierten Lizenzschlüssels: warum er nicht gefälscht werden kann

Ein guter Lizenzschlüssel ist keine zufällige Zeichenkette, die gegen eine Liste geprüft wird — er ist ein signierter Claims-Payload, den die App offline mit einem öffentlichen Schlüssel verifizieren kann, den sie ausliefert. Hier steht, was in einem signierten Schlüssel lebt, warum die Privat/Öffentlich-Trennung ihn unfälschbar macht, wie die Verifikation ohne Server funktioniert und wogegen die Signatur schützt und wogegen nicht.

Fragen Sie jemanden, wie Lizenzschlüssel funktionieren, und Sie hören oft „die App sendet den Schlüssel an einen Server, der Server prüft, ob er gültig ist”. Dieses Design existiert, aber es hat eine harte Abhängigkeit: kein Server, keine Validierung. Ein besseres Design macht den Schlüssel selbstbeweisend — er trägt seine eigenen Claims und eine kryptografische Signatur, und die Anwendung verifiziert ihn offline mit einem öffentlichen Schlüssel, den sie bereits ausliefert. Nichts an der Echtheit hängt von einem Netzwerkaufruf ab. Zu verstehen, was in einem solchen Schlüssel lebt und warum er nicht gefälscht werden kann, ist das Fundament jedes robusten Lizenzierungsschemas.

Ein Schlüssel ist ein signierter Claims-Payload

Ein moderner Lizenzschlüssel ist keine zufällige Kennung; er ist ein kleiner Satz von Claims plus einer Signatur über diese Claims. Die Claims sind die Fakten, die die Lizenz behauptet:

{
  "product": "acme-pro",
  "tier": "enterprise",
  "licensee": "acct_8f21",
  "seats": 25,
  "expiry": "2027-10-04T00:00:00Z",
  "features": ["sso", "audit-log"]
}

Für sich genommen ist diese Payload nur Daten — jeder könnte sie tippen. Was sie zu einer Lizenz macht, ist die angehängte Signatur: ein Wert, der aus der Payload mit einem privaten Schlüssel berechnet wird, den nur Ihr Lizenzserver hält. Der Schlüssel, den Ihr Kunde einfügt, ist die Payload und die Signatur zusammen, in eine kompakte, einfügbare Form codiert.

Die Privat/Öffentlich-Trennung ist der ganze Trick

Der Grund, warum der Schlüssel nicht gefälscht werden kann, ist asymmetrische Kryptografie. Es gibt zwei Schlüssel, und sie sind nicht austauschbar:

  • Der private Schlüssel lebt nur auf Ihrem Lizenzserver. Er ist das Einzige, das eine gültige Signatur erzeugen kann.
  • Der öffentliche Schlüssel ist in Ihre Anwendung eingebettet, an jeden Kunden ausgeliefert. Er kann eine Signatur verifizieren, aber keine erzeugen.

Den privaten aus dem öffentlichen Schlüssel abzuleiten ist für die verwendeten Algorithmen (wie Ed25519 oder ECDSA über P-256) rechnerisch unmöglich. Ein Angreifer, der Ihre Anwendung hat — und damit den öffentlichen Schlüssel — kann also trotzdem nichts signieren. Er kann den öffentlichen Schlüssel den ganzen Tag lesen; es hilft ihm nicht, einen neuen Schlüssel zu prägen oder einen bestehenden zu ändern, denn die Verifikation schlägt fehl, sobald ein einziges Byte der Payload oder der Signatur sich ändert.

Hier ist die Form des Signierens auf dem Server und des Verifizierens in der App, mit Ed25519:

// SERVER (private key never leaves here): sign the canonical claims bytes.
byte[] payload = CanonicalJson(claims);                 // stable byte encoding
byte[] signature = SignEd25519(payload, privateKey);     // 64-byte signature
string licenseKey = Base32(Concat(payload, signature));  // what the customer gets
// APP (ships only the public key): verify before trusting any claim.
var (payload, signature) = SplitBase32(licenseKey);
if (!VerifyEd25519(payload, signature, PublicKey))        // embedded public key
    throw new InvalidLicenseException("signature invalid");

var claims = ParseClaims(payload);
if (claims.Product != "acme-pro") throw new InvalidLicenseException("wrong product");
// expiry, tier, seats, features are now trustworthy — they were signed

Die Reihenfolge ist wichtig: verifizieren Sie zuerst die Signatur, lesen Sie dann die Claims. Ein Claim, den Sie nicht verifiziert haben, ist angreiferkontrollierte Eingabe. Sobald VerifyEd25519 true zurückgibt, ist von jedem Feld der Payload bekannt, dass es genau das ist, was Ihr Server signiert hat — unverändert und echt.

Serversign(claims, priv)LizenzschlüsselClaims + Signatureinfügbare ZeichenketteApp (bettet öffentl. Schlüssel ein)1. verify(sig, pub) → ok?2. dann tier / Ablauf / Sitze vertrauen

Warum eigenständig „gegen eine Liste prüfen” schlägt

Weil Claims und Signatur zusammen reisen und der öffentliche Schlüssel bereits in der App ist, ist die Verifikation vollständig lokal. Kein Server-Hin-und-Rück wird gebraucht, um zu wissen, dass ein Schlüssel echt und unverändert ist — was echte isolierte und Offline-Aktivierung möglich macht. Ein Server-Listen-Design kann das nicht: Es muss bei jeder Prüfung den Server erreichen, also werden eine Offline-Maschine, ein Netzwerk-Aussetzer oder ein stillgelegter Validierungs-Endpunkt alle zu Ausfällen für zahlende Kunden.

Eigenständige Schlüssel skalieren auch trivial. Es gibt keine Datenbankzeile, die pro Validierung nachzuschlagen wäre, und keinen Endpunkt, der für die Echtheit online zu halten wäre; die Mathematik ist die Autorität. Sie können auch regelmäßig einen Server kontaktieren — um Widerruf zu honorieren oder eine Lease aufzufrischen — aber das ist eine Verbesserung auf einem Schlüssel, der bereits beweisbar echt ist, keine Voraussetzung, ihm zu vertrauen.

Wie ein gefälschter oder manipulierter Schlüssel aussieht

Betrachten Sie die zwei Dinge, die ein Angreifer versuchen könnte. Einen Claim zu ändern — tier auf enterprise hochzusetzen oder expiry ein Jahrzehnt hinauszuschieben — ändert die Payload-Bytes, also passt die Signatur nicht mehr und VerifyEd25519 gibt false zurück. Einen ganzen Schlüssel zu fabrizieren erfordert, eine Signatur zu erzeugen, die gegen Ihren öffentlichen Schlüssel verifiziert, was den privaten Schlüssel erfordert, den sie nicht haben. Beide scheitern an derselben Prüfung. Das ist die Manipulationssichtbarkeit, die einem Zufallszeichenkette-plus-Datenbank-Design fehlt: Dort trägt die Zeichenkette keine Claims, also ist der Server das Einzige, das weiß, was der Schlüssel bedeutet, und der Schlüssel selbst beweist nichts.

Praktische Details, die wichtig sind

Ein paar Einzelheiten trennen ein Spielzeug von einem Produktionsschema:

  • Kanonische Codierung. Signieren Sie eine stabile Byte-Darstellung der Claims und verifizieren Sie über die exakt empfangenen Bytes. Wenn Ihr JSON-Serialisierer zwischen Signieren und Verifizieren Felder umordnet oder Leerraum variiert, werden gültige Schlüssel fehlschlagen. Eine kanonische Form (feste Feldreihenfolge, kein beiläufiger Leerraum) vermeidet das.
  • Schlüsselrotation. Irgendwann wollen Sie den Signaturschlüssel rotieren. Liefern Sie die App fähig aus, mehr als einen öffentlichen Schlüssel zu akzeptieren — den aktuellen plus jüngste Vorgänger — damit vor einer Rotation signierte Schlüssel weiter verifizieren. Bauen Sie das vom ersten Tag an ein; es nachzurüsten ist schmerzhaft.
  • Moderner Algorithmus, angemessene Größe. Bevorzugen Sie Ed25519 oder ECDSA P-256 gegenüber veralteten Optionen; sie geben kurze Signaturen und Schlüssel mit starker Sicherheit. Vermeiden Sie, Ihre eigene Signatur zu bauen oder einen symmetrischen MAC im Client zu verwenden (siehe unten).
  • Codieren Sie für Menschen, wo Schlüssel getippt werden. Wenn Kunden Schlüssel von Hand einfügen, fängt eine gruppierte Base32-Form (XXXX-XXXX-…) mit einer Prüfsumme Tippfehler, bevor die Verifikation überhaupt läuft.

Was die Signatur nicht tut

Die Signatur ist das Fundament, nicht das ganze Gebäude. Zwei Grenzen zum Klarstellen. Erstens, eine Signatur beweist Echtheit, nicht Exklusivität — ein signierter Schlüssel ist echt, egal wie viele Leute ihn kopieren, also tut Signieren nichts, um das Teilen zu stoppen. Das ist die Aufgabe von Aktivierung und Gerätebindung, darübergelegt. Zweitens, legen Sie das Signaturgeheimnis nie in den Client. Das gesamte Schema beruht darauf, dass die Signaturfähigkeit server-exklusiv ist; wenn Sie „vereinfachen”, indem Sie ein symmetrisches Geheimnis (einen HMAC-Schlüssel) in die App einbetten, damit die App sowohl signieren als auch verifizieren kann, dann kann jeder, der dieses Geheimnis extrahiert — und es lässt sich extrahieren — unbegrenzt Schlüssel fälschen. Asymmetrisches Signieren existiert genau deshalb, damit der Client nur die Macht zu verifizieren hält, nie zu erzeugen.

Zusammengenommen ist ein signierter Lizenzschlüssel eine kleine, selbstbeweisende Credential: Claims, für die Ihr Server bürgte, umhüllt von einer Signatur, die nur Ihr Server erzeugen konnte und jede Kopie Ihrer App ohne Netzwerk prüfen kann. Bekommen Sie dieses Fundament richtig — verifizieren Sie, bevor Sie vertrauen, halten Sie den privaten Schlüssel serverseitig, planen Sie Rotation — und alles andere in der Lizenzierung (Ablauf, Berechtigungen, Aktivierung, Widerruf) ist auf Boden gebaut, der nicht unter Ihren Füßen weggefälscht werden kann.

Nebula.NET testen

Härten Sie Ihren .NET-Code in wenigen Minuten — starten Sie mit der kostenlosen Edition.