Geheimnisse in Windows-Apps speichern – Klartextkonfiguration mit DPAPI vermeiden
· Go Komura · Windows-Entwicklung, Sicherheit, DPAPI, C# / .NET, Win32
Im vorigen Artikel „Checkliste für die minimale Sicherheit bei der Windows-App-Entwicklung“ wurde die minimale Grundlinie festgehalten: „Geheiminformationen nicht im Quellcode oder in Klartext-Konfiguration ablegen“ und „unter Win32 / .NET DPAPI / ProtectedData verwenden“.
Diesmal wird ein Teil davon genauer betrachtet: „DPAPI verwenden, um zumindest besser als Klartext zu sein“.
Die Zielgruppe sind Windows-Apps wie diese:
- WPF-/WinForms-/WinUI-Desktopanwendungen
- Windows-Clients in C# / .NET
- Apps, die geneigt sind, Zielanmeldeinformationen oder API-Tokens in einer lokalen Konfigurationsdatei zu speichern
Behandelt wird hier ein realistisches Design dafür, „ein Geheimnis, das zwangsläufig lokal gespeichert werden muss, wenigstens nicht unverändert im Klartext von appsettings.json liegen zu lassen“.
Es geht nicht um „perfekten Schutz, der jeden Angreifer schlägt“. Übertreibt man das, wird aus dem Sicherheitsthema plötzlich eine Gruselgeschichte.
1. Zunächst das Fazit
In der Praxis ist diese Reihenfolge des Denkens am klarsten.
- Dem Client von vornherein kein langlebiges Geheimnis mitgeben
- Windows-Authentifizierung, integrierte Authentifizierung, interaktive Benutzeranmeldung und serverseitige Geheimnisverwaltung bevorzugen
- Ist lokale Speicherung wirklich unvermeidlich, nicht im Klartext ablegen
- Unter Windows zuerst DPAPI /
ProtectedDataals erste Wahl ansetzen
- Unter Windows zuerst DPAPI /
- Bei einer gewöhnlichen Desktopanwendung
DataProtectionScope.CurrentUserals Grundeinstellung verwendenLocalMachinehat einen ziemlich eingeschränkten Einsatzbereich
- DPAPI schützt nicht bis zu dem Punkt, an dem das Gerät vollständig kompromittiert ist
- Code, der mit denselben Benutzerrechten läuft, kann grundsätzlich alles entschlüsseln, was auch dieser Benutzer entschlüsseln kann
Und der wichtigste Punkt dieses Artikels ist dieser:
„Der geheime Schlüssel muss ohnehin irgendwo gespeichert werden – ist das sicherheitstechnisch dann nicht dasselbe, ob Klartext oder DPAPI?“
Das ist zur Hälfte richtig, und die Schlussfolgerung ist falsch.
- Eigene AES-Verschlüsselung mit dem Schlüssel in derselben App oder derselben Konfiguration kommt Klartext ziemlich nahe
- Aber DPAPI verlagert die Schlüsselverwaltung an das Betriebssystem und bindet die entschlüsselungsfähige Partei an „diesen Windows-Benutzer“ oder „diesen Computer“
- Dadurch ändert sich die Widerstandsfähigkeit gegenüber Vorfällen wie dem alleinigen Durchsickern der Konfigurationsdatei, dem Mitnehmen auf einen anderen PC, Fehlversand, Backup-Leck oder versehentlicher Aufnahme ins Repository erheblich
Mit anderen Worten: Betrachtet man nur die abstrakte Aussage „der Schlüssel liegt irgendwo“, sehen sie gleich aus – aber „wer ihn wie leicht in welchem Kontext nutzen kann“ ist völlig unterschiedlich.
Einen Schlüssel unter die Fußmatte zu legen und einen Schlüssel erst nach Identitätsprüfung am Empfang auszuhändigen als „dasselbe“ zu bezeichnen, ist etwas grob.
2. Warum Klartext-Konfiguration gefährlich ist
Der Grund, warum Klartextspeicherung gefährlich ist, ist viel bodenständiger als Kryptografietheorie. In der Praxis sickern Geheimnisse meist über solche Wege durch:
- Die Konfigurationsdatei wird unverändert in Git eingecheckt
- Die Konfigurationsdatei landet komplett in einem Diagnose-ZIP
- Bei einer Support-Anfrage wird die Konfigurationsdatei angehängt
- Über Backups oder Dateifreigaben können Dritte sie lesen
- Verbindungszeichenfolgen und Tokens erscheinen unverändert in Protokollen
- Ausgeschiedene Mitarbeiter oder andere Benutzer können die Datei auf demselben Gerät lesen
Das größte Problem bei Klartext ist, dass in dem Moment, in dem er gelesen werden kann, das Geheimnis erledigt ist.
- Datei geöffnet – vorbei
- Kopiert – vorbei
- Als E-Mail-Anhang verschickt – vorbei
- Im Repository verblieben – man kümmert sich quasi dauerhaft darum
Der Angreifer muss nicht einmal besonders raffiniert sein. „Lässt sich mit einem Texteditor öffnen“ ist für sich genommen bereits ziemlich schwach.
3. Die Antwort auf „Der geheime Schlüssel wird doch ohnehin irgendwo gespeichert, ist das nicht dasselbe?“
Diese Frage ist berechtigt. Und beantwortet man sie unbedacht, wird ein Sicherheitsartikel sofort vage.
Die Antwort lautet: im Sinne von „irgendwo wird ein Schlüssel benötigt“ ja, im Sinne von „deshalb ist es dasselbe“ nein.
3.1. Was ist gleich, was ist unterschiedlich?
Tatsächlich braucht Verschlüsselung letztlich irgendeine Root of Trust. Geheimnisse sprudeln nicht kostenlos irgendwo aus dem Universum. Das ist eine strenge Welt.
Der sicherheitstechnische Unterschied entscheidet sich jedoch an diesen drei Punkten:
- Hält die App den Schlüssel direkt?
- An welche Partei ist der Schlüssel gebunden?
- Lässt sich entschlüsseln, wenn nur die Datei gestohlen wird?
Grob tabellarisch zusammengefasst sieht dieser Unterschied so aus:
| Methode | Konfigurationsdatei wird gelesen | Nur die Datei wird auf einen anderen PC mitgenommen | Wird von einem anderen Benutzer auf demselben PC gelesen | Code, der mit denselben Benutzerrechten läuft |
|---|---|---|---|---|
| Klartext | Sickert sofort durch | Sickert unverändert durch | Sickert unverändert durch | Kann selbstverständlich lesen |
| Eigene Verschlüsselung + Schlüssel in derselben Konfiguration/Binärdatei | Sickert weitgehend durch | Sickert weitgehend durch | Sickert weitgehend durch | Kann selbstverständlich entschlüsseln |
DPAPI + CurrentUser |
Allein aus der Datei nicht sofort lesbar | Normalerweise schwer zu entschlüsseln | Normalerweise schwer zu entschlüsseln | Kann entschlüsseln |
DPAPI + LocalMachine |
Allein aus der Datei nicht sofort lesbar | Außerhalb dieses PCs normalerweise schwer zu entschlüsseln | Auf demselben PC breit entschlüsselbar | Kann entschlüsseln |
Wichtig ist hier, dass DPAPI „die Datei lesen können“ von „das Geheimnis nutzen können“ trennt.
flowchart TB
CT["Chiffrat<br/>landet in Konfigurationsdatei / DB-Spalte / Diagnose-ZIP<br/>= das, was mitgenommen werden kann"]
subgraph WIN["Für die Entschlüsselung Benötigtes ── verbleibt auf Seiten des Betriebssystems, ist nicht im Chiffrat enthalten"]
UMK["Hauptschlüssel des Benutzers<br/>bei Schutz mit CurrentUser"]
MMK["Hauptschlüssel des Computers<br/>bei Schutz mit LocalMachine"]
end
CT -->|"geschützt mit CurrentUser"| UMK
CT -->|"geschützt mit LocalMachine"| MMK
UMK --> A1["Code, der als dieser Benutzer läuft<br/>→ kann entschlüsseln"]
UMK --> A2["Anderer Benutzer auf demselben PC<br/>→ kann nicht entschlüsseln"]
MMK --> B1["Code auf demselben PC<br/>→ kann auch als anderer Benutzer entschlüsseln"]
UMK --> C1["Nur das Chiffrat auf einen anderen PC kopieren<br/>→ kann nicht entschlüsseln"]
MMK --> C1
UMK --> C2["Mit dem gesamten Roamingprofil umziehen<br/>→ Schlüsselmaterial wandert mit, daher entschlüsselbar (Abschnitt 6.5)"]
Abbildung 1: Nur das Chiffrat befindet sich auf der Seite dessen, was mitgenommen werden kann; der für die Entschlüsselung nötige Hauptschlüssel bleibt auf Seiten des Betriebssystems. Allerdings reicht LocalMachine über den ganzen PC, sodass sich andere Benutzer auf demselben PC damit nicht aussperren lassen
Bei Klartext sind diese beiden Dinge identisch. Kann man die Datei lesen, kann man auch das Geheimnis lesen.
Bei DPAPI dagegen muss man, zumindest mit CurrentUser,
- als dieser Windows-Benutzer,
- in diesem Windows-Kontext,
- über den Schutzmechanismus des Betriebssystems
entschlüsseln.
Dieser Unterschied ist am Ort eines tatsächlichen Vorfalls ziemlich groß.
3.2. „Aber derselbe Benutzer kann es doch trotzdem entschlüsseln?“ – Stimmt
Das ist ein Punkt, den man nicht schönreden sollte.
Code, der mit denselben Benutzerrechten ausgeführt wird, kann grundsätzlich alles entschlüsseln, was auch dieser Benutzer entschlüsseln kann.
Das heißt, DPAPI ist nicht in erster Linie auf Situationen wie diese ausgelegt:
- Das Gerät ist bereits mit Malware kompromittiert
- Der Angreifer kann Code als dieser Benutzer ausführen
- Das Gerät ist auf Administratorebene vollständig übernommen worden
In dieser Situation kann, da die App selbst entschlüsseln kann, auch der Code des Angreifers entschlüsseln. „Aber es ist doch verschlüsselt“ ist hier keine große Beruhigung.
DPAPI wirkt vor allem auf der Seite „Dateidiebstahl, Fehlplatzierung, Offline-Mitnahme, Zugriff durch einen anderen Benutzer“.
Verwechselt man das, passieren beide Fehler gleichzeitig:
- man unterschätzt, was sich schützen lässt, und verzichtet auf den Einsatz
- man überschätzt, was sich nicht schützen lässt, und fühlt sich unbegründet sicher
Beides ist unauffällig gefährlich.
3.3. Worin liegt also der eigentliche Nutzen?
Der Nutzen von DPAPI lässt sich in einem Satz zusammenfassen:
„Das Geheimnis selbst lässt sich von der Lesbarkeit der Konfigurationsdatei entkoppeln.“
Bei Vorfällen wie diesen zeigt sich der Unterschied zwischen Klartext und DPAPI zum Beispiel:
- Ein Benutzer hat die Konfigurationsdatei versehentlich an den Support geschickt
- Die Konfigurationsdatei landete in einem Diagnose-ZIP
- Aus einem Backup ist nur die Konfigurationsdatei durchgesickert
- Sie wurde in einen Freigabeordner kopiert
- Ein Entwickler sah nur das Chiffrat und konnte den Inhalt nicht lesen
Das sind ziemlich reale Vorteile. Man kann den Radius alltäglicher Vorfälle verkleinern, ohne den Angreifer zu einem Filmhelden zu stilisieren.
4. Warum DPAPI genau richtig ist
Beim Umgang mit lokal gespeicherten Geheimnissen unter Windows liegen die praktischen Vorzüge von DPAPI in Folgendem.
4.1. Schlüsselverwaltung lässt sich an das Betriebssystem delegieren
Selbst einen AES-Schlüssel erzeugen, speichern, mit Berechtigungen versehen, rotieren, die Auswirkungen eines Lecks durchdenken und dazu noch eine Manipulationserkennung einbauen. Das ist schwerer, als es aussieht. Und macht man es unbedacht, landet der Schlüssel meist am selben Ort.
Mit DPAPI lässt sich das Problem „wie erzeuge und wo lege ich den Verschlüsselungsschlüssel ab“ aus der App-Implementierung herauslösen.
In diesem Sinn trifft man den Kern eher, wenn man DPAPI nicht als „API zur Wahl eines Verschlüsselungsalgorithmus“, sondern als „API zur Delegation der Schlüsselverwaltung an das Betriebssystem“ betrachtet.
4.2. Die entschlüsselungsfähige Partei lässt sich an einen Windows-Benutzer oder den Computer binden
Bei einer gewöhnlichen Desktopanwendung reicht in vielen Fällen die Wahl von CurrentUser.
Die Entschlüsselung setzt voraus, dass
- dieser Benutzer angemeldet ist,
- die Verarbeitung im Kontext dieses Benutzers läuft.
Dadurch erhält man die Eigenschaft, dass das reine Kopieren des Chiffrats auf einen anderen PC dieses nicht ohne Weiteres nutzbar macht.
4.3. Manipulationserkennung lässt sich leicht mit einbeziehen
Bei selbstgebauter Verschlüsselung passiert häufig, dass man mit „mit AES verschlüsselt, fertig“ die Manipulationserkennung vergisst.
DPAPI besitzt auch einen Integritätsschutz für die verschlüsselten Daten, sodass sich das Erkennen einer eigenmächtigen Änderung des Chiffrats leicht auf den betriebssystemseitigen Mechanismus abstützen lässt – ein praktischer Vorteil.
4.4. Unkompliziert aus C# / .NET nutzbar
In C# lässt sich System.Security.Cryptography.ProtectedData direkt verwenden.
Dass keine zusätzliche Bibliothek nötig ist, hilft bei reinen Windows-Apps ziemlich.
5. Was DPAPI schützt und was nicht
Hier lohnt es sich, klar zu trennen.
5.1. Was sich leichter schützen lässt
DPAPI wirkt zumindest in Situationen wie diesen:
- Klartext-Leck der Konfigurationsdatei
- Mitnahme der Datei auf einen anderen PC
- Zugriff durch einen anderen Benutzer auf demselben PC (unter der Annahme von
CurrentUser) - Leck über Backup oder Anhang
- Der Zustand „aus Versehen lesbar“ in Entwicklung und Wartung
5.2. Was nicht oder nur schwach geschützt ist
Andererseits sollte man in diesen Situationen nicht zu viel Vertrauen setzen:
- Angriffscode, der mit denselben Benutzerrechten läuft
- Vollständige Kompromittierung des Geräts selbst
- Übernahme mit Administratorrechten
- Der Klartext im Arbeitsspeicher, nachdem die App entschlüsselt hat
- Ein langlebiges Geheimnis, das an alle Clients gleich verteilt wird
Der letzte Punkt, „ein für alle Clients gemeinsames langlebiges Geheimnis“, ist besonders wichtig.
Zum Beispiel Designs wie:
- allen Kunden denselben API-Schlüssel einbetten
- auf allen Geräten dasselbe gemeinsame Passwort halten
- einen fest vorgegebenen Entschlüsselungsschlüssel verteilen, der ausschließlich auf dem Client liegt
neigen dazu, sich vom Zeitpunkt an, an dem er von einem einzigen Gerät extrahiert wird, auf das Gesamtsystem auszuwirken. Die Logik ist einfach: Kann die App auf einem einzigen Gerät entschlüsseln, lässt sich das Geheimnis dort herausholen.
DPAPI ist wirksam, um „diesen Speicherort besser als Klartext zu machen“, aber es rechtfertigt nicht, ein Geheimnis überhaupt erst auf dem Client abzulegen, das dort nicht liegen sollte.
Geheimnisse dieser Art sollte man nicht durch eine andere Speichermethode absichern, sondern eher in diese Richtung auslagern:
- serverseitig ablegen
- der Client hält nur ein Token
- benutzerbezogene Anmeldeinformationen verwenden
- befristete Tokens verwenden
6. Die Abgrenzung zwischen CurrentUser und LocalMachine
Dieser Punkt ist ziemlich wichtig. Wählt man unbedacht, ändert sich die Bedeutung.
6.1. Die Grundeinstellung ist CurrentUser
Bei einer gewöhnlichen Windows-Desktopanwendung geht man zunächst grundsätzlich von CurrentUser aus.
Geeignete Beispiele:
- Benutzerorientierte WPF-/WinForms-/WinUI-Desktopanwendungen
- Apps mit benutzerbezogenen Einstellungen oder Anmeldeinformationen
- Apps, die ihre Einstellungen unter
%LocalAppData%oder%AppData%ablegen
In diesem Fall lässt sich der Wert leicht als „Geheimnis dieses Windows-Benutzers“ behandeln.
6.2. LocalMachine hat einen ziemlich eingeschränkten Einsatzbereich
LocalMachine wirkt praktisch, ist für eine gewöhnliche Desktopanwendung aber zu weitreichend.
Geeignet ist es zum Beispiel für Fälle wie:
- ein Windows-Dienst auf einer vertrauenswürdigen Einzelzweck-Maschine
- ein Geheimnis, das nur von einem bestimmten Prozess auf dieser Maschine genutzt wird
- einen Fall, in dem eine Nutzung über Anmeldebenutzer hinweg auf demselben Gerät zwingend erforderlich ist
Die zu beachtenden Punkte wiegen jedoch schwer.
- Es lässt sich breit von Prozessen entschlüsseln, die auf diesem PC laufen
- Bei gemeinsam genutzten Geräten, RDS, Sprungservern und Umgebungen mit mehreren Benutzern wird es leicht gefährlich
- Wählt man es nach dem Motto „bequem, weil alle es nutzen können“, gerät man meist später in Schwierigkeiten
Und die Beweggründe, aus denen man zu LocalMachine neigt, sind meist diese drei:
- Es bleibt auch nach einem Benutzerwechsel lesbar
- Auch ein Dienst kann darauf zugreifen
- Es ist bequem, wenn es einfach funktioniert
Das ist alles „bequem“, aber nicht „geschützt“.
Wählt man LocalMachine bei einer gewöhnlichen Desktopanwendung, weitet man die Entschlüsselungsmöglichkeit auf andere Prozesse auf demselben PC aus, wodurch sich die Bedeutung erheblich ändert.
6.3. Bei Zweifel so denken
- Gewöhnliche UI-App ->
CurrentUser - Sonderfall, bei dem wirklich auf Maschinenebene geschützt werden muss ->
LocalMachine - Jeder Benutzer muss entschlüsseln können, aber auf dem Gerät sind auch andere Benutzer -> meist lohnt sich eine Überarbeitung des Designs
6.4. Bei Diensten oder Impersonation ist etwas mehr Vorsicht nötig
Kommen Windows-Dienste oder Impersonation ins Spiel, wird die Bedeutung von CurrentUser etwas schwerer.
- Wer ist das Ausführungskonto?
- Ist das Profil dieses Kontos geladen?
- In welchem Kontext findet die Entschlüsselung statt?
Verschiebt sich das, kommt es leicht zu „es hat verschlüsselt, lässt sich aber nicht entschlüsseln“.
Bei Diensteinsätzen reicht „einfach CurrentUser“ nicht immer aus.
Bei Impersonation ist ein typischer, auch in Microsoft Learn dokumentierter Fehler „Key not valid for use in specified state.“. DPAPI hält die Schlüsseldaten im Benutzerprofil, daher kann ohne geladenes Profil nicht entschlüsselt werden. Vor dem Impersonate-Aufruf muss das Profil des Zielbenutzers geladen sein.
6.5. Fälle kennen, in denen im Betrieb „nicht mehr entschlüsselt werden kann“
Schmerzhafter als die Verschlüsselung selbst ist in der Praxis oft der Vorfall, dass sich nicht mehr entschlüsseln lässt. Da DPAPI die entschlüsselungsfähige Partei an den Windows-Benutzer bzw. den Computer bindet, wird die Datei unlesbar, sobald diese Bindung reißt.
Diese fünf Fälle sollte man vorab kennen:
| Fall | Was passiert | Vorsorge |
|---|---|---|
| Passwort-Reset durch einen Administrator | Der an das Benutzerpasswort gebundene Schutz löst sich, und der Zugriff auf mit DPAPI geschützte Daten kann verloren gehen. Auch Microsofts Support-Informationen beschreiben den Fall, dass nach einem administrativen Passwort-Reset kein Zugriff mehr auf DPAPI-Daten besteht | Das Geheimnis so gestalten, dass es sich „erneut beschaffen“ lässt. Bei Entschlüsselungsfehlern zur erneuten Eingabe führen |
| Neuanlage des Profils | Ein neues Profil besitzt anderes Schlüsselmaterial, daher lässt sich das bisherige Chiffrat nicht mehr entschlüsseln | Die Konfigurationsdatei versionieren und einen Entschlüsselungsfehler nicht zum Absturz führen lassen |
| Nur das Chiffrat wird auf einen anderen PC kopiert | Das für die Entschlüsselung nötige Schlüsselmaterial liegt im Benutzerprofil, daher lässt sich mit CurrentUser allein das mitgenommene Chiffrat nicht lesen (das ist die Kehrseite der in 3.1 genannten Stärke) |
So gestalten, dass pro Gerät neu gespeichert wird |
| Roamingprofil | Das lässt sich lesen. Da das Schlüsselmaterial zusammen mit dem Profil umzieht, hält auch Microsoft Learn ausdrücklich fest, dass ein Benutzer mit Roamingprofil von einem anderen Computer im Netzwerk aus entschlüsseln kann. Behandelt man das wie die vorherige Zeile, werden bei einer Migration unnötig Anmeldeinformationen neu erzeugt | Nicht pauschal annehmen, „anderer PC = nicht lesbar“. Erst prüfen, ob Roaming vorliegt, dann das Migrationsverfahren festlegen |
| Wechsel des Ausführungskontos eines Dienstes | Ändert sich das Ausführungskonto zwischen Schutz und Entschlüsselung, lässt sich mit CurrentUser nicht mehr lesen |
Ein Verfahren zum erneuten Schützen bei Kontowechsel in den Betrieb aufnehmen |
Kurz gesagt: Man schreibt den Code unter der Annahme, dass ProtectedData.Unprotect fehlschlagen kann. Schlägt die Entschlüsselung fehl, wird eine CryptographicException ausgelöst; diese fängt man ab und leitet zur erneuten Eingabe über.
using System;
using System.Security.Cryptography;
using System.Text;
// protectedBase64: aus der Konfigurationsdatei gelesenes Chiffrat (Base64)
// entropy: denselben Wert wie beim Schützen übergeben. Auch null ist möglich
static bool TryUnprotect(string protectedBase64, byte[]? entropy, out string plaintext)
{
plaintext = string.Empty;
try
{
byte[] plainBytes = ProtectedData.Unprotect(
Convert.FromBase64String(protectedBase64),
optionalEntropy: entropy,
scope: DataProtectionScope.CurrentUser);
plaintext = Encoding.UTF8.GetString(plainBytes);
return true;
}
catch (CryptographicException)
{
// Entschlüsselung nicht möglich = die Umgebung hat sich vermutlich geändert.
// Hier nicht abstürzen, sondern beim Aufrufer zur erneuten Eingabe führen
return false;
}
catch (FormatException)
{
// Wenn das Base64 selbst fehlerhaft ist
return false;
}
}
Wenn sich Support-Anfragen häufen mit „habe verschlüsselt, kann aber nicht entschlüsseln“, liegt meist einer dieser Tabellenfälle vor.
7. Minimale Implementierungsrichtlinien
Geht es einer Windows-App nur darum, „mit dem Klartext in der Konfigurationsdatei aufzuhören“, muss das Design nicht besonders komplex sein. Ein paar Punkte sollte man aber nicht auslassen.
7.1. Nur das Geheimnis schützen
Statt die gesamte Konfiguration komplett zu verschlüsseln, ist es einfacher zu handhaben, wenn man zunächst nur die geheimen Einträge schützt.
Zum Beispiel so aufteilen:
- Server-URL
- Benutzername
- DB-Name
- Feature-Flags
können oft weiterhin im Klartext bleiben.
Dagegen sind
- Passwörter
- API-Tokens
- Refresh-Tokens
- Anmeldeinformationen für Netzwerkfreigaben
Schutzziele.
Bei dieser Aufteilung erhält man:
- leichter zu bearbeitende Konfiguration
- leichter überprüfbare Diffs
- klar erkennbar, was geheim ist
- insgesamt einfacheren Betrieb
7.2. Den Speicherort grundsätzlich pro Benutzer wählen
Bei einer gewöhnlichen Desktopanwendung sollte der Speicherort grundsätzlich benutzerbezogen sein.
%LocalAppData%\Vendor\App\settings.json%AppData%\Vendor\App\settings.json
Zumindest sollte man es nicht achtlos unter dem Installationsordner oder an einem leicht freigebbaren Ort ablegen.
Selbst mit DPAPI-Schutz führt eine nachlässige ACL am Speicherort zu Aussagen wie „das Chiffrat kann gelesen werden“, „die Konfigurationsstruktur ist sichtbar“, „Bedienfehler passieren“. Verteidigung wirkt besser gestaffelt als einstufig.
7.3. optionalEntropy ist kein allmächtiger zweiter Schlüssel
An ProtectedData lässt sich optionalEntropy übergeben.
Das ist praktisch, aber kein „magischer zweiter Schlüssel, der alles sicher macht, sobald man ihn in die Binärdatei einbettet“.
- Legt man ihn in dieselbe Datei, ist er kein Geheimnis
- Bettet man ihn als festen Wert in die Binärdatei ein, ist er ebenfalls kein starkes Geheimnis
- Trotzdem ist er zur Zweckerkennung und zur Vermeidung von Fehlanwendung nützlich
In der Praxis ist es angemessen,
- den App-Namen,
- den Verwendungszweck,
- eine Versionskennung
als festen Byte-String zu übergeben und damit „das versehentliche Akzeptieren von Chiffrat aus einem anderen Verwendungszweck“ zu verhindern.
7.4. Chiffrat darf in Git – das ist damit nicht gemeint
Auch das ist unauffällig wichtig.
Das DPAPI-Chiffrat ist deutlich besser als Klartext, aber das heißt nicht, dass man die gesamte Konfigurationsdatei ins Repository aufnehmen darf.
Der Grund ist einfach:
- Chiffrat bleibt lange bestehen
- Irgendwann könnte derselbe Gerätekontext erneut hergestellt werden
- Die Datei enthält auch andere Informationen als das Geheimnis
- Es entsteht eine Kultur nach dem Motto „ist ja geschützt, also darf man nachlässig damit umgehen“
„Besser als Klartext“ und „überall sicher, wo man es ablegt“ sind völlig verschiedene Dinge.
7.5. Nicht ins Protokoll ausgeben
Überraschend häufig ist das Muster, dass man nach der Entschlüsselung alles durch eine Protokollausgabe zunichtemacht.
- Bei einem Verbindungsfehler die gesamte Verbindungszeichenfolge ausgeben
- Bei einem API-401 den Authorization-Header stehen lassen
- Geheimnisse in Ausnahmemeldungen einmischen
Macht man das, wird trotz Abschaffung des Konfigurationsdatei-Klartexts letztlich das Protokoll zum Klartextlager. Traurig, aber ziemlich praxisnah.
8. Minimales Implementierungsbeispiel in C# / .NET
8.1. Zuerst ist eine Referenz hinzuzufügen
ProtectedData wirkt so, als gehöre es zur BCL, doch je nach Ziel-Framework unterscheidet sich, „woher es kommt“. Stolpert man hier, lässt sich der Typname ProtectedData nicht auflösen.
| Ziel | Erforderlicher Schritt | Quelle |
|---|---|---|
| .NET Framework | Dem Projekt eine System.Security-Assemblyreferenz hinzufügen |
System.Security.dll |
| .NET Core / .NET 5 oder neuer (einschließlich .NET 6 / 8) | Das NuGet-Paket System.Security.Cryptography.ProtectedData hinzufügen |
System.Security.Cryptography.ProtectedData.dll |
Dieses Paket ist in keinem der Shared Frameworks von .NET Core / .NET 5 oder neuer enthalten. Auch bei einem Windows-Ziel wie net8.0-windows ist die Referenz ausdrücklich erforderlich.
dotnet add package System.Security.Cryptography.ProtectedData
Noch ein Punkt, den man vor der Implementierung kennen sollte:
ProtectedData ist nur für Windows. Da es von DPAPI abhängt, löst ein Aufruf unter .NET auf einer anderen Plattform als Windows eine PlatformNotSupportedException aus. Bei einer von vornherein plattformübergreifenden Codebasis wählt man wie in 10.1 von Anfang an ein anderes Design.
8.2. Minimale Implementierung
Im Folgenden ein minimales Beispiel, das eine in der Konfigurationsdatei zu speichernde Zeichenfolge mit CurrentUser schützt.
Zur Zweckerkennung wird eine feste optionalEntropy eingefügt, doch bitte nicht als geheimen Schlüssel verstehen.
using System;
using System.Security.Cryptography;
using System.Text;
public static class DpapiSecretProtector
{
// Zur Zweckerkennung. Kein zweiter geheimer Schlüssel.
private static readonly byte[] Entropy =
Encoding.UTF8.GetBytes("ComComponent:DesktopApp:SettingsSecret:v1");
public static string ProtectToBase64(string plaintext)
{
ArgumentNullException.ThrowIfNull(plaintext);
byte[] plainBytes = Encoding.UTF8.GetBytes(plaintext);
byte[] protectedBytes = Array.Empty<byte>();
try
{
protectedBytes = ProtectedData.Protect(
plainBytes,
optionalEntropy: Entropy,
scope: DataProtectionScope.CurrentUser);
return Convert.ToBase64String(protectedBytes);
}
finally
{
Array.Clear(plainBytes, 0, plainBytes.Length);
if (protectedBytes.Length > 0)
{
Array.Clear(protectedBytes, 0, protectedBytes.Length);
}
}
}
public static string UnprotectFromBase64(string protectedBase64)
{
ArgumentNullException.ThrowIfNull(protectedBase64);
byte[] protectedBytes = Convert.FromBase64String(protectedBase64);
byte[] plainBytes = Array.Empty<byte>();
try
{
plainBytes = ProtectedData.Unprotect(
protectedBytes,
optionalEntropy: Entropy,
scope: DataProtectionScope.CurrentUser);
return Encoding.UTF8.GetString(plainBytes);
}
finally
{
Array.Clear(protectedBytes, 0, protectedBytes.Length);
if (plainBytes.Length > 0)
{
Array.Clear(plainBytes, 0, plainBytes.Length);
}
}
}
}
Die Verwendung ist einfach.
string protectedPassword = DpapiSecretProtector.ProtectToBase64(password);
// In JSON o. Ä. speichern
// settings.DbPasswordProtected = protectedPassword;
string password = DpapiSecretProtector.UnprotectFromBase64(settings.DbPasswordProtected);
Die Konfigurationsdatei kann dann zum Beispiel so aussehen.
{
"ApiBaseUrl": "https://api.example.com/",
"UserName": "app-user",
"PasswordProtected": "AQAAANCMnd8BFdERjHoAwE..."
}
Das Gute an dieser Form:
- URL und Benutzername lassen sich normal bearbeiten
- Nur das Passwort ist geschützt
- Die Konfigurationsstruktur bleibt übersichtlich
- Weniger vorfallanfällig, als es im Klartext zu belassen
9. Designs, die trotzdem gefährlich sind
Selbst mit DPAPI im Einsatz sind folgende Designs noch gefährlich.
9.1. Den entschlüsselten Wert lange herumreichen
Man möchte vermeiden, den entschlüsselten Wert
- ins Protokoll auszugeben,
- auf dem Bildschirm anzuzeigen,
- in eine Ausnahme aufzunehmen,
- dauerhaft auf einem langlebigen Objekt liegen zu lassen.
„Beim Speichern verschlüsselt“ und „auch während der Nutzung sicher“ sind unterschiedliche Probleme.
9.2. Allen Installationen ein gemeinsames Geheimnis geben
Ein Design, bei dem alle Benutzer denselben API-Schlüssel besitzen, wird durch Speicherung mit DPAPI nicht grundlegend gelöst. Grund und Alternative, wohin man ausweicht, sind in 5.2 zusammengefasst.
9.3. LocalMachine wählen, weil es „bequem“ ist
Auch das kommt wirklich häufig vor. Aber „bequem“ heißt nicht „geschützt“. Die Beweggründe, die zur Wahl verleiten, und was sich dabei ausweitet, stehen in 6.2. Bei Unsicherheit die drei Zeilen aus 6.3 ansehen.
9.4. Sich mit einer eigenen Verschlüsselung in Sicherheit wiegen
Statt DPAPI folgende Implementierungen einzusetzen:
- einen AES-Schlüssel in den Quellcode einbetten
- einen AES-Schlüssel in einem anderen Feld der Konfigurationsdatei ablegen
- eine „etwas verschleierte Zeichenfolge“ als Schlüssel behandeln
bringt meist nur wenig.
Zwischen „nicht Klartext“ und „sicher“ liegt eine ziemlich große Kluft.
10. Fälle, in denen DPAPI nicht ausreicht
DPAPI ist praktisch, aber nicht allmächtig. In folgenden Fällen sollte man eine andere Option in Betracht ziehen.
10.1. Wenn es auch außerhalb von Windows laufen soll
DPAPI / ProtectedData sind auf Windows ausgerichtet.
Eine plattformübergreifende App lässt sich auf dieser Grundlage nicht aufbauen.
10.2. Wenn dasselbe Geheimnis auf mehreren Geräten und von mehreren Benutzern genutzt werden soll
Eine Anforderung wie „dasselbe Chiffrat auf mehreren PCs entschlüsseln“ oder „von mehreren Benutzern gemeinsam nutzen“ liegt außerhalb der Stärke von DPAPI, das an „dieses Gerät, diesen Benutzer“ bindet.
In diesem Fall sollte man ein anderes, zur Anforderung passendes Design in Betracht ziehen, etwa:
- serverseitige Geheimnisverwaltung
- eine Infrastruktur für Anmeldeinformationen
- Windows-Authentifizierung / integrierte Authentifizierung
- einen Anmeldeinformationsspeicher für die App
10.3. Wenn das zu Speichernde selbst eine Benutzeranmeldeinformation ist
Wenn das, was gespeichert werden soll, eindeutig ein Paar aus
- Benutzername
- Passwort
ist, ist es naheliegender, den von Windows bereitgestellten Anmeldeinformationsspeicher zu verwenden, statt es mit DPAPI in eine eigene Datei zu schreiben. Das ist in der Praxis ein häufiger Zweifelspunkt, daher hier ein Vergleich.
| Aspekt | DPAPI (ProtectedData) |
Credential Locker (PasswordVault) |
Credential Manager (CredWrite / CredRead) |
|---|---|---|---|
| Speicherort | Eine selbst gewählte Datei (wie das Chiffrat abgelegt wird, entscheidet die App) | Von Windows verwalteter Anmeldeinformationsspeicher | Von Windows verwalteter Anmeldeinformationsspeicher |
| Speicherbares | Beliebige Byte-Folge (Verbindungszeichenfolge, Token oder auch nur ein Teil der Konfiguration) | Paar aus Benutzername und Passwort | Anmeldeinformationen (typspezifische Struktur) |
| API | System.Security.Cryptography |
WinRT-Windows.Security.Credentials |
Win32 (wincred.h / Advapi32.dll) |
| Aus Desktop-Apps nutzbar? | Direkt nutzbar | Nicht nur aus WinUI, sondern auch aus WPF / WinForms nutzbar (Konfiguration für WinRT-API-Aufrufe nötig) | Direkt nutzbar |
| Synchronisation | Keine | Roaming zwischen Geräten über das Microsoft-Konto | Keine (lokale, benutzergebundene Anmeldeinformationsmenge) |
| Einschränkung | Praktisch keine | Bis zu 20 Einträge pro App. Nicht für große Datenmengen gedacht | An die aktuelle Anmeldesitzung des Tokens gebunden |
| Verwaltende Instanz | Die App (Speicherort und ACL bestimmt sie selbst) | Das Betriebssystem (Speicherort muss nicht selbst entworfen werden) | Das Betriebssystem (verwaltbar über den Anmeldeinformations-Manager der Systemsteuerung) |
Die Faustregel für die Wahl lautet:
- Zu speichern ist ein Paar aus Benutzername und Passwort, und die Anzahl ist gering -> Credential Locker / Credential Manager sind die erste Wahl. Weder Speicherort noch ACL müssen selbst entworfen werden
- Das zu Speichernde hat nicht die Form „Benutzername + Passwort“ -> Verbindungszeichenfolgen, API-Tokens, Refresh-Tokens oder Teile einer Konfigurationsdatei passen besser zu DPAPI. Damit befasst sich dieser Artikel
- Es soll zwischen Geräten mitgenommen werden -> Das Roaming des Credential Locker greift hier. Bei DPAPI mit
CurrentUserist es dagegen gerade ein Vorteil, „nicht mitgenommen zu werden“ – hier stehen die Ziele einander entgegen - Viele Einträge / große Datenmenge -> Man stößt an das 20-Einträge-Limit des Credential Locker. Dann weicht man mit DPAPI auf eine eigene Datei aus
Zu beachten ist außerdem, dass auch der Anmeldeinformationsspeicher intern auf dem Schutzmechanismus des Betriebssystems aufsetzt – es handelt sich also nicht um eine Rangfolge „sicherer als DPAPI“ oder „DPAPI ist unterlegen“. Praktisch entscheidet man nach der Form dessen, was gespeichert werden soll, und danach, ob Roaming nötig ist.
Und unabhängig davon, wofür man sich entscheidet, lohnt es sich bei einer neuen App, zuerst ein passwortloses Verfahren wie Windows Hello / Passkeys zu prüfen. Braucht man von vornherein kein langlebiges Passwort, ist das die stärkste Lösung überhaupt.
Der Schwerpunkt dieses Artikels bleibt aber die praktische DPAPI-Grundlinie dafür, „auf einem Windows-Client den Konfigurationsdatei-Klartext abzuschaffen“.
11. Empfohlene Prioritätenreihenfolge in der Praxis
Zum Schluss: Ist man in der Praxis unsicher, hilft diese Reihenfolge beim Einordnen. Von oben nach unten prüfen und nur dann eine Stufe weiter absteigen, wenn die Bedingung nicht erfüllt ist.
flowchart TD
Q1{"Lässt sich vermeiden, dem Gerät<br/>ein langlebiges Geheimnis zu geben?"}
Q1 -->|"lässt sich vermeiden"| A1["Priorität 1: nicht halten<br/>(Windows-Authentifizierung, kurzlebige Tokens)"]
Q1 -->|"lässt sich nicht vermeiden"| Q2{"Lässt sich das Geheimnis<br/>pro Benutzer trennen?"}
Q2 -->|"lässt sich nicht trennen"| A2["Prüfen, ob ein gemeinsamer<br/>Schlüssel vorliegt, und das Design überarbeiten"]
Q2 -->|"lässt sich trennen"| QF{"Hat das zu Speichernde die Form<br/>Benutzername + Passwort? (Abschnitt 10.3)"}
QF -->|"dieses Paar, und wenige Einträge"| QR1{"Muss es zwischen Geräten<br/>mitgenommen werden?"}
QR1 -->|"ja"| QA{"Ein Gerät, das über ein<br/>Microsoft-Konto synchronisiert? (Abschnitt 10.3)"}
QA -->|"ja"| CL2["Roaming des<br/>Credential Locker nutzen"]
QA -->|"Domänen-/lokales Konto"| SRV
QR1 -->|"nein"| CL["Credential Locker /<br/>Credential Manager"]
QF -->|"Token o. Ä., andere Form"| QR2{"Muss es zwischen Geräten<br/>mitgenommen werden?"}
QR2 -->|"ja"| SRV["Mit DPAPI nicht mitnehmbar.<br/>Serverseitig verwalten (Abschnitt 10.2)"]
QR2 -->|"nein"| Q3{"Von wie vielen Konten aus muss<br/>dasselbe Geheimnis entschlüsselt werden?"}
Q3 -->|"nur eines genügt (der Benutzer selbst<br/>oder ein dediziertes Dienstkonto)"| A3["Priorität 3: DPAPI + CurrentUser<br/>Bei unbeaufsichtigter Ausführung das Laden<br/>des Profils prüfen (Abschnitt 6.4)"]
Q3 -->|"muss von mehreren<br/>Konten entschlüsselt werden"| Q4{"Lässt sich ausschließen, dass<br/>andere Benutzer auf dem Gerät sind?"}
Q4 -->|"lässt sich ausschließen"| A4["Priorität 4: DPAPI + LocalMachine<br/>Als Ausnahmefall behandeln und begründen"]
Q4 -->|"lässt sich nicht ausschließen"| A5["Auch andere Benutzer können entschlüsseln.<br/>Das Authentifizierungsverfahren überarbeiten"]
Abbildung 2: Reihenfolge bei der Wahl der Speichermethode. Zuerst die Form des Geheimnisses und den Roaming-Bedarf klären, dann erst zu DPAPI übergehen. LocalMachine wählt man nicht aus Bequemlichkeit, sondern als Ausnahme, wenn keine andere Option infrage kommt
Priorität 1: Von vornherein nicht halten
- Windows-Authentifizierung
- Integrierte Authentifizierung
- Interaktive Anmeldung
- Serverseitige Geheimnishaltung
- Kurzlebige Tokens
Priorität 2: Auf benutzerbezogene Geheimnisse setzen
- Benutzerbezogen statt gemeinsam genutzt
- Erneuerbare Tokens statt langlebiger fester Anmeldeinformationen
- Einen für alle Clients gemeinsamen Schlüssel vermeiden
Priorität 3: Ist lokale Speicherung nötig, DPAPI
- Normalerweise
CurrentUser - Speicherort pro Benutzer
- Nur die geheimen Einträge schützen
- Nicht im Protokoll ausgeben
Priorität 4: LocalMachine als Ausnahme behandeln
- Ist es wirklich auf Maschinenebene nötig?
- Kommen auf diesem Gerät keine anderen Benutzer vor?
- Ist es als Dienstdesign angemessen?
12. Zusammenfassung
Muss eine Windows-App vertrauliche Informationen in einer Konfigurationsdatei speichern, möchte man vermeiden, sie im Klartext liegen zu lassen.
Und auf die Frage:
„Der Schlüssel wird doch ohnehin irgendwo gespeichert, ist das nicht dasselbe?“
lautet die praxisnahe Antwort so:
- Bei eigener Verschlüsselung mit dem Schlüssel am selben Ort: ziemlich dasselbe
- DPAPI ist nicht dasselbe
- Die Schlüsselverwaltung lässt sich an das Betriebssystem delegieren
- Die entschlüsselungsfähige Partei lässt sich an einen Windows-Benutzer / Computer binden
- Ein Leck der Datei allein muss nicht sofort zu einem Leck des Geheimnisses werden
- Allerdings löst es nicht
- Code, der mit denselben Benutzerrechten läuft,
- ein vollständig kompromittiertes Gerät,
- ein langlebiges, gemeinsames Geheimnis, das gar nicht erst auf dem Client liegen sollte
Kurz gesagt: DPAPI ist keine allmächtige Festungsmauer. Aber es hat ungefähr den Effekt, die durchsichtige Fensterscheibe eines Klartext-Konfigurationsdatei gegen wenigstens ein anständiges Fenster auszutauschen.
In der Praxis von Windows-Clients ist dieser Unterschied ziemlich groß. Am besten beginnt man damit, genau diesen Punkt nicht zu verfehlen.
13. Referenzen
- Vorheriger Artikel: Checkliste für die minimale Sicherheit bei der Windows-App-Entwicklung
- Microsoft Learn:
CryptProtectDatahttps://learn.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata - Microsoft Learn:
ProtectedDatahttps://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata?view=windowsdesktop-10.0 - Microsoft Learn:
DataProtectionScopehttps://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.dataprotectionscope?view=windowsdesktop-10.0 - Microsoft Learn: How to: Use Data Protection https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection
- Microsoft Learn: Credential locker for Windows apps https://learn.microsoft.com/en-us/windows/apps/develop/security/credential-locker
- Microsoft Learn:
CredWrite(Win32-API des Windows Credential Manager) https://learn.microsoft.com/en-us/windows/win32/api/wincred/nf-wincred-credwritew - NuGet: System.Security.Cryptography.ProtectedData https://www.nuget.org/packages/System.Security.Cryptography.ProtectedData
- Microsoft-Support: Kein Zugriff mehr auf DPAPI-Daten, nachdem ein Administrator das Passwort zurückgesetzt hat https://support.microsoft.com/en-us/topic/you-cannot-access-dpapi-data-after-an-administrator-resets-your-password-on-a-windows-server-2012-based-domain-controller-4aa890cd-12b5-fe5c-9e68-06244e70673d
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Wie man in einer Windows-App konkret nur die „Vorgänge, die Administratorrechte brauchen“ isoliert
Eine konkrete Anleitung, wie Sie die UI einer Windows-App bei asInvoker belassen und nur die Vorgänge, die Administratorrechte brauchen, ...
Eine Mindest-Sicherheitscheckliste für die Windows-Anwendungsentwicklung
Ordnet für WPF / WinForms / WinUI / C++ / C#-Businessanwendungen die Grundlagen zu Rechten, Signatur, Updates, Geheimnissen, HTTPS, Einga...
Die Tiefen von Windows I/O (Teil 6, Finale) ── Filtertreiber und Minifilter: Warum Procmon und Virenscanner sich in die I/O einklinken können
Der Abschluss einer bebilderten Artikelserie über Windows-Filtertreiber und Minifilter. Er behandelt den Filter-Manager und Altitudes, Pr...
Zugangsdaten in PowerShell sicher handhaben — Klartext-Passwörter aus Ihren Skripten verbannen
Ein praktischer Leitfaden, um Klartext-Passwörter aus PowerShell-Skripten zu entfernen und sicher zu speichern: was SecureString wirklich...
Wenn die eigene Windows-App als Virus gemeldet wird — Umgang mit Fehlalarmen von Microsoft Defender und den Auswirkungen auf die Leistung
Wir legen dar, wie richtig reagiert wird, wenn Microsoft Defender die eigene Windows-App als Malware meldet: wie moderne Antivirus-Erkenn...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Die Wahl der Speichermethode für Anmeldeinformationen, der Speicherort für benutzerbezogene Einstellungen und der Umgang mit Protokollausgaben betreffen das Gesamtdesign einer Windows-App – ein Thema, das gut zur Windows-App-Entwicklung passt.
Technische Beratung und Design-Review
Wer bei einer bestehenden App die Klartext-Konfiguration überarbeiten oder die Abgrenzung zwischen DPAPI und Credential Locker klären möchte, ist mit technischer Beratung und Design-Review gut bedient.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Was ist DPAPI?
- DPAPI (Data Protection API) ist ein von Windows bereitgestellter Datenschutzmechanismus, der die Schlüsselverwaltung an das Betriebssystem delegiert und die entschlüsselungsfähige Partei an diesen Windows-Benutzer oder diesen Computer bindet. Aus C# / .NET lässt es sich über die Klasse System.Security.Cryptography.ProtectedData nutzen, ohne zusätzliche Bibliotheken hinzuzufügen. Es ist weniger eine API zur Wahl eines Verschlüsselungsalgorithmus als vielmehr eine API, die die Schlüsselverwaltung an das Betriebssystem delegiert – so trifft man den Kern besser. Es ist eine realistische Option, um Passwörter oder API-Tokens in Konfigurationsdateien nicht im Klartext liegen zu lassen.
- Der Schlüssel muss doch ohnehin irgendwo gespeichert werden – ist das dann nicht dasselbe wie Klartext oder DPAPI?
- Nein, das ist nicht dasselbe. Legt man den Schlüssel bei einer selbstgebauten AES-Verschlüsselung in derselben App oder Konfigurationsdatei ab, kommt das dem Klartext ziemlich nahe. DPAPI dagegen verlagert die Schlüsselverwaltung an das Betriebssystem und bindet die entschlüsselungsfähige Partei an den Windows-Benutzer oder den Computer. Dadurch ändert sich die Widerstandsfähigkeit gegenüber Vorfällen wie dem alleinigen Durchsickern der Konfigurationsdatei, dem Mitnehmen auf einen anderen PC, einem Fehlversand, einem Backup-Leck oder einer versehentlichen Aufnahme ins Repository erheblich. Der entscheidende Unterschied zu Klartext ist, dass DPAPI „die Datei lesen können“ von „das Geheimnis nutzen können“ trennen kann.
- Was schützt DPAPI nicht?
- Code, der mit denselben Benutzerrechten ausgeführt wird, kann grundsätzlich alles entschlüsseln, was auch dieser Benutzer entschlüsseln kann. Deshalb schützt DPAPI nicht bei einem bereits mit Malware kompromittierten Gerät, bei einer Übernahme mit Administratorrechten und auch nicht den Klartext im Arbeitsspeicher nach der Entschlüsselung. Auch ein langlebiges Geheimnis, das an alle Clients gleich verteilt wird, ist durch DPAPI-Speicherung nicht grundlegend abgesichert, da es sich, sobald es von einem einzigen Gerät extrahiert wurde, leicht auf das Gesamtsystem auswirkt. DPAPI wirkt vor allem gegen Dateidiebstahl, Fehlplatzierung, Offline-Mitnahme und den Zugriff durch andere Benutzer.
- Sollte man bei DataProtectionScope CurrentUser oder LocalMachine verwenden?
- Bei einer gewöhnlichen Windows-Desktopanwendung ist CurrentUser die Grundregel. Es lässt sich als Geheimnis dieses Benutzers behandeln, und man erhält die Eigenschaft, dass das reine Kopieren des Chiffrats auf einen anderen PC nicht ohne Weiteres nutzbar ist. LocalMachine lässt sich dagegen breit von Prozessen entschlüsseln, die auf diesem PC laufen, wodurch es bei gemeinsam genutzten Geräten oder Umgebungen mit mehreren Benutzern gefährlich werden kann; die Einsatzfälle beschränken sich weitgehend auf Windows-Dienste auf einer vertrauenswürdigen Einzelzweck-Maschine. Wählt man LocalMachine, weil „alle es nutzen können und das bequem ist“, gerät man damit meist später in Schwierigkeiten.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.