Wann würde ich einen SecureString in .NET benötigen?

179

Ich versuche, den Zweck von .NETs SecureString zu verstehen. Von MSDN:

Eine Instanz der System.String-Klasse ist unveränderlich und kann, wenn sie nicht mehr benötigt wird, nicht programmgesteuert für die Speicherbereinigung geplant werden. Das heißt, die Instanz ist nach ihrer Erstellung schreibgeschützt und es ist nicht möglich vorherzusagen, wann die Instanz aus dem Computerspeicher gelöscht wird. Wenn ein String-Objekt vertrauliche Informationen wie ein Kennwort, eine Kreditkartennummer oder persönliche Daten enthält, besteht daher das Risiko, dass die Informationen nach ihrer Verwendung angezeigt werden, da Ihre Anwendung die Daten nicht aus dem Computerspeicher löschen kann.

Ein SecureString-Objekt ähnelt einem String-Objekt darin, dass es einen Textwert hat. Der Wert eines SecureString-Objekts wird jedoch automatisch verschlüsselt, kann geändert werden, bis Ihre Anwendung es als schreibgeschützt markiert, und von Ihrer Anwendung oder dem .NET Framework-Garbage Collector aus dem Computerspeicher gelöscht werden.

Der Wert einer Instanz von SecureString wird automatisch verschlüsselt, wenn die Instanz initialisiert oder der Wert geändert wird. Ihre Anwendung kann die Instanz unveränderlich machen und weitere Änderungen verhindern, indem Sie die MakeReadOnly-Methode aufrufen.

Ist die automatische Verschlüsselung die große Auszahlung?

Und warum kann ich nicht einfach sagen:

SecureString password = new SecureString("password");

anstatt

SecureString pass = new SecureString();
foreach (char c in "password".ToCharArray())
    pass.AppendChar(c);

Welchen Aspekt von SecureString vermisse ich?

Richard Morgan
quelle
3
11 Jahre später und MS empfiehlt keine SecureStringNeuentwicklung mehr: github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
Matt Thomas

Antworten:

4

Ich würde SecureString nicht mehr verwenden. Sieht so aus, als würden PG-Leute die Unterstützung dafür einstellen. Möglicherweise sogar in Zukunft - https://github.com/dotnet/apireviews/tree/master/2015-07-14-securestring .

Wir sollten die Verschlüsselung von SecureString auf allen Plattformen in .NET Core entfernen. - Wir sollten SecureString veralten. - SecureString sollte in .NET Core wahrscheinlich nicht verfügbar gemacht werden

Joe Healy
quelle
1
Der Link ist tot, aber er scheint weiterzumachen: docs.microsoft.com/en-us/dotnet/api/… .. mit einigen sehr schwachen Anleitungen zum Ausführen des Pfads "Keine Anmeldeinformationen verwenden" - github.com/dotnet/platform- kompatibel / blob / master / docs / DE0001.md .. trauen Sie sich nicht, ein Passwort zu verwenden, um den privaten Schlüssel Ihrer Zertifikate zu schützen!
Felickz
1
Nach 11 Jahren scheint diese Antwort nun die "neue" richtige zu sein. Die Links scheinen veraltet zu sein, aber die Anleitung von MS lautet: SecureString sollte nicht verwendet werden
Richard Morgan
109

Einige Teile des Frameworks, die derzeit verwendet werden SecureString:

Der Hauptzweck besteht darin, die Angriffsfläche zu reduzieren, anstatt sie zu beseitigen. SecureStringssind im RAM "angeheftet", damit der Garbage Collector sie nicht verschiebt oder Kopien davon erstellt. Außerdem wird sichergestellt, dass der Klartext nicht in die Swap-Datei oder in Core-Dumps geschrieben wird. Die Verschlüsselung ähnelt eher einer Verschleierung und wird jedoch einen entschlossenen Hacker nicht aufhalten, der in der Lage wäre, den symmetrischen Schlüssel zu finden, der zum Ver- und Entschlüsseln verwendet wird.

Wie andere gesagt haben, liegt der Grund, warum Sie ein SecureStringZeichen für Zeichen erstellen müssen, in dem ersten offensichtlichen Fehler, etwas anderes zu tun: Vermutlich haben Sie den geheimen Wert bereits als einfache Zeichenfolge. Worum geht es also?

SecureStrings sind der erste Schritt zur Lösung eines Henne-Ei-Problems. Obwohl die meisten aktuellen Szenarien erfordern, dass sie wieder in reguläre Zeichenfolgen umgewandelt werden, um sie überhaupt nutzen zu können, bedeutet ihre Existenz im Framework jetzt eine bessere Unterstützung für sie in der Zukunft - zumindest bis zu einem Punkt, an dem Ihr Programm nicht das schwache Glied sein muss.

Chris Wenham
quelle
2
Ich bin darauf gestoßen und habe mir die Password-Eigenschaft von ProcessStartInfo angesehen. Ich habe nicht einmal auf den Typ geachtet, sondern ihn einfach auf eine reguläre Zeichenfolge gesetzt, bis der Compiler mich angebellt hat.
Richard Morgan
Es wird nicht einfach sein, den symmetrischen Verschlüsselungsschlüssel zu finden, da SecureString auf DPAPI basiert, das einen Schlüssel nicht genau im Klartext speichert ...
AviD
1
Außerdem ist es nicht so sehr das Henne-Ei-Problem, da es kein Ersatz für die Verschlüsselung im Speicher ist, sondern eine Problemumgehung für unveränderliche, verwaltete .NET-Zeichenfolgen.
AviD
2
"Sie haben vermutlich den geheimen Wert bereits als einfache Zeichenfolge. Worum geht es also?" Gibt es eine Antwort auf diese Frage? Es scheint bestenfalls eine "besser als nichts" -Lösung zu sein, wenn Sie beabsichtigen, ein Passwort über einen längeren Zeitraum im Speicher zu behalten.
xr280xr
2
Was ist mit ein paar einfachen Codebeispielen für die Verwendung? Ich glaube, ich würde besser verstehen, wie und wann ich es verwenden soll.
Codea
37

Bearbeiten : Verwenden Sie SecureString nicht

Aktuelle Richtlinien besagen nun, dass die Klasse nicht verwendet werden sollte. Die Details finden Sie unter folgendem Link: https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

Aus dem Artikel:

DE0001: SecureString sollte nicht verwendet werden

Motivation

  • Der Zweck von SecureStringbesteht darin, zu vermeiden, dass Geheimnisse als einfacher Text im Prozessspeicher gespeichert werden.
  • Selbst unter Windows gibt es SecureStringjedoch kein Betriebssystemkonzept.
    • Dadurch wird das Fenster nur kürzer. Dies wird nicht vollständig verhindert, da .NET die Zeichenfolge weiterhin in eine Nur-Text-Darstellung konvertieren muss.
    • Der Vorteil ist, dass die Klartextdarstellung nicht als Instanz von System.String- die Lebensdauer des nativen Puffers ist kürzer.
  • Der Inhalt des Arrays ist außer in .NET Framework unverschlüsselt.
    • In .NET Framework wird der Inhalt des internen char-Arrays verschlüsselt. .NET unterstützt die Verschlüsselung nicht in allen Umgebungen, weder aufgrund fehlender APIs noch aufgrund von Problemen bei der Schlüsselverwaltung.

Empfehlung

Nicht SecureStringfür neuen Code verwenden. Beachten Sie beim Portieren von Code nach .NET Core, dass der Inhalt des Arrays nicht im Speicher verschlüsselt ist.

Der allgemeine Ansatz beim Umgang mit Anmeldeinformationen besteht darin, diese zu vermeiden und sich stattdessen auf andere Mittel zur Authentifizierung zu verlassen, z. B. Zertifikate oder Windows-Authentifizierung.

Ende der Bearbeitung: Originalzusammenfassung unten

Viele gute Antworten; Hier ist eine kurze Zusammenfassung dessen, was besprochen wurde.

Microsoft hat die SecureString-Klasse implementiert, um eine bessere Sicherheit mit vertraulichen Informationen (wie Kreditkarten, Kennwörtern usw.) zu gewährleisten. Es bietet automatisch:

  • Verschlüsselung (bei Speicherauszügen oder Seiten-Caching)
  • in Erinnerung bleiben
  • Möglichkeit, als schreibgeschützt zu markieren (um weitere Änderungen zu verhindern)
  • Sichere Konstruktion, indem NICHT zugelassen wird, dass eine konstante Zeichenfolge übergeben wird

Derzeit ist die Verwendung von SecureString begrenzt, es wird jedoch eine bessere Einführung in der Zukunft erwartet.

Basierend auf diesen Informationen sollte der Konstruktor des SecureString nicht nur eine Zeichenfolge nehmen und in das char-Array aufteilen, da die Schreibweise der Zeichenfolge den Zweck von SecureString zunichte macht.

Zusätzliche Information:

  • Ein Beitrag aus dem .NET-Sicherheitsblog, der sich mit dem hier behandelten Thema befasst.
  • Und noch eine , die es noch einmal besucht und ein Tool erwähnt, mit dem der Inhalt des SecureString gesichert werden kann.

Bearbeiten: Ich fand es schwierig, die beste Antwort zu finden, da es in vielen gute Informationen gibt; Schade, dass es keine unterstützten Antwortoptionen gibt.

Richard Morgan
quelle
20

Kurze Antwort

warum kann ich nicht einfach sagen:

SecureString password = new SecureString("password");

Denn jetzt hast du passwordin Erinnerung; ohne die Möglichkeit, es zu löschen - genau das ist der Punkt von SecureString .

Lange Antwort

Der Grund, warum SecureString existiert, ist, dass Sie ZeroMemory nicht zum Löschen vertraulicher Daten verwenden können, wenn Sie damit fertig sind. Es ist vorhanden, um ein Problem zu lösen, das aufgrund der CLR besteht.

In einer regulären nativen Anwendung würden Sie Folgendes aufrufen SecureZeroMemory:

Füllt einen Speicherblock mit Nullen.

Hinweis : SecureZeroMemory ist identisch mit ZeroMemory, außer dass der Compiler es nicht entfernt.

Das Problem ist, dass Sie nichtZeroMemory oder SecureZeroMemoryin .NET anrufen können . Und in .NET sind Zeichenfolgen unveränderlich. Sie können den Inhalt der Zeichenfolge nicht einmal wie in anderen Sprachen überschreiben :

//Wipe out the password
for (int i=0; i<password.Length; i++)
   password[i] = \0;

Also was kannst du tun? Wie bieten wir in .NET die Möglichkeit, ein Passwort oder eine Kreditkartennummer aus dem Speicher zu löschen, wenn wir damit fertig sind?

Der einzige Weg , es kann getan werden wäre die Zeichenfolge in einigen zu platzieren nativen Speicherblock, in dem Sie können dann rufen ZeroMemory. Ein natives Speicherobjekt wie:

  • ein BSTR
  • ein HGLOBAL
  • Nicht verwalteter CoTaskMem-Speicher

SecureString gibt die verlorene Fähigkeit zurück

In .NET können Strings nicht gelöscht werden, wenn Sie damit fertig sind:

  • sie sind unveränderlich; Sie können ihren Inhalt nicht überschreiben
  • du kannst nicht Disposevon ihnen
  • Ihre Bereinigung ist dem Müllsammler ausgeliefert

SecureString ist eine Möglichkeit, die Sicherheit von Strings zu umgehen und deren Bereinigung bei Bedarf zu gewährleisten.

Sie haben die Frage gestellt:

warum kann ich nicht einfach sagen:

SecureString password = new SecureString("password");

Denn jetzt hast du passwordin Erinnerung; ohne eine Möglichkeit, es abzuwischen. Es bleibt dort hängen, bis die CLR beschließt, diesen Speicher wiederzuverwenden. Sie haben uns wieder dorthin gebracht, wo wir angefangen haben. Eine laufende Anwendung mit einem Kennwort, das wir nicht entfernen können und bei der ein Speicherauszug (oder Prozessmonitor) das Kennwort sehen kann.

SecureString verwendet die Datenschutz-API, um die im Speicher verschlüsselte Zeichenfolge zu speichern. Auf diese Weise ist die Zeichenfolge in Swap-Dateien, Absturzabbildern oder sogar im Fenster für lokale Variablen nicht vorhanden, wenn ein Kollege Ihre Anforderungen überprüft.

Wie lese ich das Passwort?

Dann ist die Frage: Wie interagiere ich mit der Zeichenfolge? Sie wollen absolut keine Methode wie:

String connectionString = secureConnectionString.ToString()

denn jetzt bist du wieder da, wo du angefangen hast - ein Passwort, das du nicht loswerden kannst. Sie wollen zwingen Entwickler die empfindliche Saite richtig zu handhaben - so dass es kann aus dem Gedächtnis gewischt werden.

Aus diesem Grund bietet .NET drei praktische Hilfsfunktionen, um einen SecureString in einem nicht verwalteten Speicher zu speichern:

Sie konvertieren die Zeichenfolge in einen nicht verwalteten Speicher-Blob, behandeln ihn und löschen ihn dann erneut.

Einige APIs akzeptieren SecureStrings . Zum Beispiel in ADO.net 4.5 die SqlConnection.Credential nimmt einen Satz SqlCredential :

SqlCredential cred = new SqlCredential(userid, password); //password is SecureString
SqlConnection conn = new SqlConnection(connectionString);
conn.Credential = cred;
conn.Open();

Sie können das Kennwort auch innerhalb einer Verbindungszeichenfolge ändern:

SqlConnection.ChangePassword(connectionString, cred, newPassword);

Und es gibt viele Stellen in .NET, an denen sie aus Kompatibilitätsgründen weiterhin eine einfache Zeichenfolge akzeptieren und diese dann schnell umdrehen und in einen SecureString einfügen.

Wie füge ich Text in den SecureString ein?

Dies lässt immer noch das Problem:

Wie bekomme ich überhaupt ein Passwort in den SecureString?

Dies ist die Herausforderung, aber es geht darum, dass Sie über Sicherheit nachdenken.

Manchmal ist die Funktionalität bereits für Sie bereitgestellt. Beispielsweise kann das WPF PasswordBox- Steuerelement das eingegebene Kennwort direkt als SecureString zurückgeben :

PasswordBox.SecurePassword-Eigenschaft

Ruft das aktuell von der PasswordBox gehaltene Kennwort als SecureString ab .

Dies ist hilfreich, da Sie überall dort, wo Sie eine Rohzeichenfolge weitergegeben haben, jetzt das Typsystem haben, das sich darüber beschwert, dass SecureString nicht mit Zeichenfolge kompatibel ist. Sie möchten so lange wie möglich arbeiten, bevor Sie Ihren SecureString wieder in eine normale Zeichenfolge konvertieren müssen.

Das Konvertieren eines SecureString ist einfach genug:

  • SecureStringToBSTR
  • PtrToStringBSTR

wie in:

private static string CreateString(SecureString secureString)
{
    IntPtr intPtr = IntPtr.Zero;
    if (secureString == null || secureString.Length == 0)
    {
        return string.Empty;
    }
    string result;
    try
    {
        intPtr = Marshal.SecureStringToBSTR(secureString);
        result = Marshal.PtrToStringBSTR(intPtr);
    }
    finally
    {
        if (intPtr != IntPtr.Zero)
        {
            Marshal.ZeroFreeBSTR(intPtr);
        }
    }
    return result;
}

Sie wollen einfach nicht, dass du es tust.

Aber wie bekomme ich einen String in einen SecureString? Nun, was Sie tun müssen, ist, überhaupt kein Passwort mehr in einem String zu haben. Sie mussten es in etwas anderem haben. Sogar ein Char[]Array wäre hilfreich.

Dann können Sie jedes Zeichen anhängen und den Klartext löschen, wenn Sie fertig sind:

for (int i=0; i < PasswordArray.Length; i++)
{
   password.AppendChar(PasswordArray[i]);
   PasswordArray[i] = (Char)0;
}

Sie müssen Ihr Passwort in einem Speicher speichern, den Sie löschen können. Laden Sie es von dort in den SecureString.


tl; dr: SecureString ist vorhanden, um das Äquivalent von ZeroMemory bereitzustellen .

Einige Leute sehen keinen Sinn darin , das Kennwort des Benutzers aus dem Speicher zu löschen, wenn ein Gerät gesperrt ist , oder Tastatureingaben aus dem Speicher zu löschen, nachdem sie authentifiziert wurden . Diese Personen verwenden SecureString nicht.

Ian Boyd
quelle
14

Es gibt nur sehr wenige Szenarien, in denen Sie SecureString in der aktuellen Version des Frameworks sinnvoll einsetzen können. Es ist wirklich nur nützlich für die Interaktion mit nicht verwalteten APIs - Sie können es mit Marshal.SecureStringToGlobalAllocUnicode marshallen.

Sobald Sie es in / aus einem System.String konvertieren, haben Sie seinen Zweck besiegt.

Das MSDN- Beispiel generiert aus der Konsoleneingabe jeweils ein SecureString-Zeichen und übergibt die sichere Zeichenfolge an eine nicht verwaltete API. Es ist ziemlich verworren und unrealistisch.

Sie können erwarten, dass zukünftige Versionen von .NET mehr Unterstützung für SecureString bieten, wodurch es nützlicher wird, z.

  • SecureString Console.ReadLineSecure () oder ähnliches zum Lesen von Konsoleneingaben in einen SecureString ohne den gesamten verschlungenen Code im Beispiel.

  • WinForms TextBox-Ersatz, in dem die TextBox.Text-Eigenschaft als sichere Zeichenfolge gespeichert wird, damit Kennwörter sicher eingegeben werden können.

  • Erweiterungen zu sicherheitsrelevanten APIs, damit Kennwörter als SecureString übergeben werden können.

Ohne das oben Genannte ist SecureString von begrenztem Wert.

Joe
quelle
12

Ich glaube, der Grund, warum Sie anstelle einer flachen Instanziierung Zeichen anhängen müssen, liegt darin, dass im Hintergrund die Übergabe von "Kennwort" an den Konstruktor von SecureString diese "Kennwort" -String in den Speicher legt, wodurch der Zweck einer sicheren Zeichenfolge zunichte gemacht wird.

Durch das Anhängen speichern Sie jeweils nur ein Zeichen in einem Speicher, der wahrscheinlich nicht physisch nebeneinander liegt, was die Rekonstruktion der ursprünglichen Zeichenfolge erheblich erschwert. Ich könnte mich hier irren, aber so wurde es mir erklärt.

Der Zweck der Klasse besteht darin, zu verhindern, dass sichere Daten über einen Speicherauszug oder ein ähnliches Tool verfügbar gemacht werden.

JoshReedSchramm
quelle
11

MS stellte fest, dass es in bestimmten Fällen, in denen der Server (Desktop, was auch immer) zum Absturz gebracht wurde, Zeiten gab, in denen die Laufzeitumgebung einen Speicherauszug ausführte, der den Inhalt des Speichers enthüllte. Secure String verschlüsselt es im Speicher, um zu verhindern, dass der Angreifer den Inhalt des Strings abrufen kann.

kemiller2002
quelle
5

Einer der großen Vorteile eines SecureString besteht darin, dass vermieden werden soll, dass Ihre Daten aufgrund von Seiten-Caching auf der Festplatte gespeichert werden. Wenn Sie ein Kennwort im Speicher haben und dann ein großes Programm oder einen großen Datensatz laden, wird Ihr Kennwort möglicherweise in die Auslagerungsdatei geschrieben, wenn Ihr Programm nicht mehr über genügend Arbeitsspeicher verfügt. Mit einem SecureString werden zumindest die Daten nicht unbegrenzt im Klartext auf Ihrer Festplatte gespeichert.

Jason Z.
quelle
4

Ich denke, das liegt daran, dass die Zeichenfolge sicher sein soll, dh ein Hacker sollte sie nicht lesen können. Wenn Sie es mit einer Zeichenfolge initialisieren, kann der Hacker die ursprüngliche Zeichenfolge lesen.

OregonGhost
quelle
4

Nun, wie in der Beschreibung angegeben, wird der Wert verschlüsselt gespeichert, was bedeutet, dass ein Speicherauszug Ihres Prozesses den Wert der Zeichenfolge nicht anzeigt (ohne ziemlich ernsthafte Arbeit).

Der Grund, warum Sie einen SecureString nicht einfach aus einer konstanten Zeichenfolge erstellen können, liegt darin, dass Sie dann eine unverschlüsselte Version der Zeichenfolge im Speicher haben würden. Wenn Sie sich darauf beschränken, die Zeichenfolge in Teilen zu erstellen, verringert sich das Risiko, dass die gesamte Zeichenfolge gleichzeitig gespeichert wird.

Mark Bessey
quelle
2
Wenn sie die Konstruktion von einer konstanten Zeichenfolge einschränken, würde die Zeile foreach (char c in "password" .ToCharArray ()) dies zunichte machen, nein? Es sollte pass.AppendChar ('p') sein; pass.AppendChar ('a'); etc?
Richard Morgan
Ja, Sie können den geringen Schutz, den SecureString Ihnen bietet, leicht wegwerfen. Sie versuchen es schwer zu machen, sich vollständig in den Fuß zu schießen. Offensichtlich muss es eine Möglichkeit geben, den Wert in einen SecureString hinein und aus ihm heraus zu bringen, sonst können Sie ihn für nichts verwenden.
Mark Bessey
1

Ein weiterer Anwendungsfall ist, wenn Sie mit Zahlungsanwendungen (POS) arbeiten und einfach keine unveränderlichen Datenstrukturen zum Speichern vertraulicher Daten verwenden können, da Sie ein sorgfältiger Entwickler sind. Beispiel: Wenn ich vertrauliche Kartendaten oder Autorisierungsmetadaten in unveränderlichen Zeichenfolgen speichere, ist es immer dann der Fall, wenn diese Daten nach dem Verwerfen für einen längeren Zeitraum im Speicher verfügbar sind. Ich kann es nicht einfach überschreiben. Ein weiterer großer Vorteil, wenn solche sensiblen Daten verschlüsselt gespeichert werden.

römisch
quelle