Einen Maschinen-Fingerabdruck entwerfen, der stabil, aber nicht brüchig ist
Node-Locking bindet eine Lizenz an ein Gerät, was bedeutet, dass Sie einen Fingerabdruck brauchen, der einzigartig genug ist, um eine Maschine zu identifizieren, und doch stabil genug, um ein RAM-Upgrade zu überstehen. Hier steht, wie man ihn aus gewichteten Hardware-Signalen baut, mit Toleranz abgleicht, zum Schutz der Privatsphäre hasht und die VM- und Hardware-Wechsel-Fälle behandelt, über die naive Implementierungen stolpern.
Node-Locking — eine Lizenz an ein bestimmtes Gerät zu binden — ist nur so gut wie der Fingerabdruck, auf dem es ruht. Verfehlen Sie den Fingerabdruck in die eine Richtung, ist er zu locker: Er kollidiert über Maschinen hinweg, und ein Schlüssel läuft still überall. Verfehlen Sie ihn in die andere Richtung, ist er zu brüchig: Er ändert sich, wenn der Nutzer RAM hinzufügt oder eine Netzwerkkarte tauscht, und ein zahlender Kunde ist plötzlich aus Software ausgesperrt, die er rechtmäßig besitzt. Ein guter Maschinen-Fingerabdruck fädelt dieses Nadelöhr — einzigartig genug, um ein Gerät zu identifizieren, stabil genug, um das gewöhnliche Leben dieses Geräts zu überstehen. Hier steht, wie man ihn baut.
Die Spannung: Einzigartigkeit vs. Stabilität
Jedes Hardware-Signal, das Sie zum Fingerabdruck heranziehen könnten, liegt irgendwo auf einem Spektrum zwischen stabil und einzigartig, und beide ziehen gegeneinander:
- Stabil, weniger einzigartig: die OS-Installationskennung (eine einmal bei der OS-Installation geschriebene GUID), der Maschinenname. Sie ändern sich selten, können sich aber über geklonte Images wiederholen.
- Einzigartig, weniger stabil: eine MAC-Adresse, eine Festplatten-Seriennummer. Sehr unterscheidend, aber eine MAC ändert sich mit einem neuen Adapter oder einer Dockingstation, und Festplatten werden ersetzt.
- Dazwischen: Mainboard-/BIOS-Kennungen und CPU-Details — recht einzigartig, recht stabil, aber auf manchen virtuellen Maschinen abwesend oder geteilt.
Kein einzelnes Signal ist zugleich perfekt stabil und perfekt einzigartig, was genau der Grund ist, warum das Hashen eines Werts — oder schlimmer, das Verketten mehrerer zu einem Hash — einen brüchigen Fingerabdruck erzeugt. Der Ausweg ist nicht, das „beste” Signal zu wählen; es ist, mehrere zu kombinieren und mit Toleranz abzugleichen.
Sammeln Sie mehrere Signale, jedes gewichtet
Sammeln Sie eine Handvoll unabhängiger Signale und weisen Sie jedem ein Gewicht zu, das widerspiegelt, wie sehr Sie seiner Stabilität vertrauen. Eine Skizze in C#:
record Signal(string Name, string Value, int Weight);
IEnumerable<Signal> CollectSignals() => new[]
{
new Signal("os-install-id", ReadMachineGuid(), 40), // very stable
new Signal("board-id", ReadBaseboardId(), 30), // stable
new Signal("cpu-id", ReadCpuSignature(), 20), // stable-ish
new Signal("primary-mac", ReadPrimaryMac(), 10), // volatile
};
Die Gewichte zählen mehr als die genauen Signale. Die OS-Installations-GUID und das Mainboard tragen den Großteil der Identität; die MAC trägt ein wenig bei, darf das Ergebnis aber nicht allein entscheiden. Entscheidend ist, dass Sie die Signale getrennt halten, statt sie in einen einzigen Hash zu falten, denn der Abgleich muss sehen können, welche Signale sich änderten.
Gleichen Sie mit Toleranz ab, nicht mit Gleichheit
Die naive Prüfung — „ist der gespeicherte Fingerabdruck gleich dem aktuellen?” — ist der Brüchigkeits-Bug. Vergleichen Sie stattdessen Signal für Signal und summieren Sie das Gewicht der Signale, die noch übereinstimmen. Das Gerät ist „dasselbe”, wenn das übereinstimmende Gewicht eine Schwelle überschreitet:
int MatchScore(IReadOnlyList<Signal> stored, IReadOnlyList<Signal> current)
{
int score = 0;
foreach (var s in stored)
{
var c = current.FirstOrDefault(x => x.Name == s.Name);
if (c is not null && FixedTimeEquals(c.Value, s.Value))
score += s.Weight;
}
return score; // 0..100
}
bool IsSameDevice(IReadOnlyList<Signal> stored, IReadOnlyList<Signal> current)
=> MatchScore(stored, current) >= 70; // tolerate up to 30 points of drift
Mit den obigen Gewichten ändert ein RAM-Upgrade nichts in dieser Menge; ein neuer Netzwerkadapter lässt die primary-mac (10 Punkte) fallen, erreicht aber noch 90; selbst ein Wechsel von CPU und MAC überschreitet noch 70, solange OS-Installations-GUID und Mainboard übereinstimmen. Unterdessen teilt eine wirklich andere Maschine keinen der Anker mit hohem Gewicht und erreicht weit unter der Schwelle. Eine Zahl — die Schwelle — wird zum Regler, den Sie zwischen „zu locker” und „zu brüchig” einstellen.
Hashen Sie auf dem Gerät, senden Sie nur das undurchsichtige Ergebnis
Das Fingerprinting berührt Hardware-Kennungen, also entwerfen Sie es so, dass möglichst wenig die Maschine verlässt. Berechnen Sie die Signale lokal und senden Sie dem Server einen undurchsichtigen Hash pro Signal — nie die rohen Seriennummern. Der Server speichert Werte, die er nicht in „dieser Kunde besitzt genau dieses Mainboard” zurückverwandeln kann, was Ihnen Gerätebindung gibt, ohne ein Dossier identifizierbarer Hardware zusammenzustellen.
// Salt with the product/key so the same hardware yields different
// fingerprints across products — no cross-product correlation.
string Hash(string raw, string salt) =>
Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(salt + ":" + raw)));
Pro Produkt (oder pro Lizenz) zu salzen bedeutet, dass dasselbe Gerät für jedes Produkt einen unzusammenhängenden Fingerabdruck erzeugt, sodass zwei Anbieter nie „dieselbe Maschine” aus ihren gespeicherten Fingerabdrücken korrelieren können. Senden Sie die gehashten Signale und ihre Gewichte; die obige Abgleichslogik funktioniert identisch auf Hashes. Das ist der datenschutzfreundliche Standard, und er ist auch für Sie strikt besser — es gibt schlicht weniger sensible Daten zu halten.
Die Fälle, über die naive Implementierungen stolpern
Zwei Realitäten brechen Fingerabdrücke, die nur je auf dem Laptop eines Entwicklers getestet wurden:
Virtuelle Maschinen und Container. Geklonte VM-Images können eine OS-Installations-GUID und Mainboard-Kennungen teilen, sodass viele „verschiedene” Maschinen identisch aussehen — oder, mit Randomisierung pro Klon, derselbe logische Server bei jedem Start neu aussieht. Für virtualisierte oder kurzlebige Umgebungen ist Hardware-Fingerprinting oft ganz das falsche Werkzeug; ein schwebendes oder gleichzeitiges Modell, das gleichzeitige Nutzung zählt, passt besser. (Siehe schwebende Lizenzen und Node-Locking und Sitzverwaltung dafür, wann man was wählt.)
Legitimer Hardware-Wechsel. Irgendwann stirbt ein Mainboard, wird ein Laptop ersetzt, eine Festplatte getauscht. Toleranz kauft Ihnen Zeit, aber ein kompletter Neuaufbau überschreitet die Schwelle — und das soll er, denn das ist wirklich ein neues Gerät. Die Antwort ist ein anmutiger Reaktivierungspfad: Wenn der Score unter die Schwelle fällt, scheitern Sie nicht still; behandeln Sie es als neue Aktivierung gegen das Gerätekontingent des Schlüssels und lassen Sie den Kunden seinen Sitz verschieben. Der Server verfolgt Aktivierungen pro Schlüssel bereits für Sitzlimits, also ist ein abgedrifteter Fingerabdruck nur eine Anfrage, ein neues Gerät zu binden, dem gleichen Sitzbudget unterworfen — keine Sperre.
Die Form eines guten Fingerabdrucks
Zusammengenommen ist ein robuster Maschinen-Fingerabdruck: mehrere unabhängige Signale, jedes danach gewichtet, wie stabil es ist; ein Abgleich, der übereinstimmendes Gewicht gegen eine einstellbare Schwelle summiert, statt exakte Gleichheit zu verlangen; Hashing pro Signal auf dem Gerät mit einem produktspezifischen Salt, sodass nur undurchsichtige Werte die Maschine verlassen; und ein expliziter Reaktivierungspfad für den Tag, an dem die Hardware sich wirklich ändert. Bauen Sie ihn so, und Node-Locking tut seine Arbeit — ein Schlüssel, ein Gerät — ohne ein RAM-Upgrade in ein Support-Ticket zu verwandeln. Bauen Sie ihn als einzelnen Hash einer MAC-Adresse, und Sie werden mehr Zeit damit verbringen, sich bei zahlenden Kunden zu entschuldigen, als die wenigen zu stoppen, die Schlüssel teilen.
Nebula.NET testen
Härten Sie Ihren .NET-Code in wenigen Minuten — starten Sie mit der kostenlosen Edition.