Ist SecureString jemals in einer C # -Anwendung praktisch?

224

Fühlen Sie sich frei, mich zu korrigieren, wenn meine Annahmen hier falsch sind, aber lassen Sie mich erklären, warum ich frage.

Entnommen aus MSDN, a SecureString:

Stellt Text dar, der vertraulich behandelt werden sollte. Der Text wird aus Datenschutzgründen verschlüsselt und bei Nichtgebrauch aus dem Computerspeicher gelöscht.

Ich verstehe, es ist absolut sinnvoll, ein Passwort oder andere private Informationen in einem SecureStringüber a zu speichern System.String, weil Sie steuern können, wie und wann es tatsächlich im Speicher gespeichert wird, weil a System.String:

ist unveränderlich und kann, wenn es 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.

Bei einer GUI-Anwendung (z. B. einem SSH-Client) muss die Anwendung SecureString jedoch aus a erstellt werden System.String . Alle Textsteuerelemente verwenden eine Zeichenfolge als zugrunde liegenden Datentyp .

Dies bedeutet, dass jedes Mal, wenn der Benutzer eine Taste drückt, die alte Zeichenfolge verworfen wird und eine neue Zeichenfolge erstellt wird, um den Wert im Textfeld darzustellen, selbst wenn eine Kennwortmaske verwendet wird. Und wir können nicht steuern, wann oder ob einer dieser Werte aus dem Speicher verworfen wird .

Jetzt ist es Zeit, sich beim Server anzumelden. Erraten Sie, was? Sie müssen zur Authentifizierung eine Zeichenfolge über die Verbindung übergeben . Konvertieren wir also unsere SecureStringin eine System.String.... und jetzt haben wir eine Zeichenfolge auf dem Heap, ohne dass er gezwungen werden kann, die Garbage Collection zu durchlaufen (oder Nullen in den Puffer zu schreiben).

Mein Punkt ist : Egal , was Sie tun, irgendwo entlang der Linie, die SecureStringsich geht in eine umgewandelt werden System.String, es bedeutet , zumindest gibt es auf dem Heap zu einem bestimmten Zeitpunkt (ohne Gewähr für Garbage Collection).

Mein Punkt ist nicht : ob es Möglichkeiten gibt, das Senden einer Zeichenfolge an eine SSH-Verbindung zu umgehen oder zu umgehen, dass ein Steuerelement eine Zeichenfolge speichert (benutzerdefiniertes Steuerelement erstellen). Für diese Frage können Sie "ssh-Verbindung" durch "Anmeldeformular", "Registrierungsformular", "Zahlungsformular", "Lebensmittel-Sie-würden-Ihren-Welpen-aber-nicht-Ihre-Kinder-Formular füttern" ersetzen. etc.

  • Ab wann wird die Verwendung eines SecureStringtatsächlich praktikabel?
  • Lohnt es sich jemals die zusätzliche Entwicklungszeit, um die Verwendung eines System.StringObjekts vollständig zu beseitigen ?
  • Ist es der springende Punkt SecureString, einfach die Zeit zu reduzieren, die sich a System.Stringauf dem Heap befindet (um das Risiko zu verringern, zu einer physischen Auslagerungsdatei zu wechseln)?
  • Wenn ein Angreifer hat bereits die Mittel für eine Heap - Prüfung, dann wird er höchstwahrscheinlich entweder (A) hat bereits die Mittel , Tastenanschläge zu lesen, oder (B) , die bereits auf den Rechner hat ... So würde mit einem SecureStringverhindern , dass er in der Einstiegs- Daten sowieso?
  • Ist das nur "Sicherheit durch Dunkelheit"?

Tut mir leid, wenn ich die Fragen zu dick stelle, hat mich die Neugier gerade überwältigt. Fühlen Sie sich frei, einige oder alle meiner Fragen zu beantworten (oder mir zu sagen, dass meine Annahmen völlig falsch sind). :) :)

Steven Jeffries
quelle
25
Denken Sie daran, dass dies SecureStringkeine wirklich sichere Zeichenfolge ist. Dies ist lediglich eine Möglichkeit, das Zeitfenster zu verkürzen, in dem jemand Ihr Gedächtnis überprüfen und die vertraulichen Daten erfolgreich abrufen kann. Dies ist nicht kugelsicher und sollte es auch nicht sein. Aber die Punkte, die Sie ansprechen, sind sehr gültig. Siehe auch
Theodoros Chatzigiannakis
1
@ TheodorosChatzigiannakis, ja, das habe ich mir ziemlich genau gedacht. Ich habe heute den ganzen Tag damit verbracht, mir Gedanken darüber zu machen, wie ich ein Passwort für die Lebensdauer der Anwendung sicher speichern kann, und ich habe mich nur gefragt, ob es sich lohnt.
Steven Jeffries
1
Wahrscheinlich nicht wert. Andererseits könnten Sie sich gegen ein extremes Szenario verteidigen. Extrem nicht in dem Sinne, dass es unwahrscheinlich ist, dass jemand diese Art von Zugriff auf Ihren Computer erhält, sondern in dem Sinne, dass der Computer (in jeder Hinsicht) als gefährdet angesehen wird, wenn jemand diese Art von Zugriff erhält, und ich nicht. Ich glaube nicht, dass es irgendeine Sprache oder Technik gibt, mit der Sie sich vollständig dagegen verteidigen können.
Theodoros Chatzigiannakis
8
Es schützt davor, dass ein Passwort jahrelang sichtbar ist , lange nachdem alle aufgehört haben zu glauben, dass es ein Problem geben könnte. Auf einer weggeworfenen Festplatte, die in der Auslagerungsdatei gespeichert ist. Es ist wichtig, den Speicher zu schrubben, damit die Chancen dafür gering sind. Mit System.String ist dies nicht möglich, da es unveränderlich ist. Es erfordert eine Infrastruktur, auf die heutzutage nur wenige Programme Zugriff haben und die mit nativem Code zusammenarbeiten, sodass die nützlichen Methoden von Marshal.SecureStringXxx () immer seltener werden. Oder eine anständige Möglichkeit, den Benutzer dazu aufzufordern :)
Hans Passant
1
SecureString ist eine tiefgreifende Sicherheitstechnik. Der Kompromiss zwischen Entwicklungskosten und Sicherheitsgewinn ist in den meisten Situationen nicht günstig. Es gibt nur sehr wenige gute Anwendungsfälle dafür.
usr

Antworten:

237

Es gibt tatsächlich sehr praktische Anwendungen von SecureString.

Wissen Sie, wie oft ich solche Szenarien gesehen habe? (Die Antwort lautet: viele!):

  • Ein Passwort wird versehentlich in einer Protokolldatei angezeigt.
  • Irgendwo wird ein Kennwort angezeigt - einmal zeigte eine GUI eine Befehlszeile der Anwendung an, die ausgeführt wurde, und die Befehlszeile bestand aus einem Kennwort. Ups .
  • Verwenden des Speicherprofilers zum Profilieren von Software mit Ihrem Kollegen. Kollege sieht Ihr Passwort im Speicher. Klingt unwirklich? Überhaupt nicht.
  • Ich habe einmal eine RedGateSoftware verwendet, die im Ausnahmefall den "Wert" lokaler Variablen erfassen konnte, was erstaunlich nützlich ist. Ich kann mir jedoch vorstellen, dass versehentlich "String-Passwörter" protokolliert werden.
  • Ein Absturzspeicherauszug, der ein Zeichenfolgenkennwort enthält.

Wissen Sie, wie Sie all diese Probleme vermeiden können? SecureString. Es stellt im Allgemeinen sicher, dass Sie keine dummen Fehler als solche machen. Wie vermeidet es das? Indem Sie sicherstellen, dass das Kennwort im nicht verwalteten Speicher verschlüsselt ist und auf den tatsächlichen Wert nur zugegriffen werden kann, wenn Sie zu 90% sicher sind, was Sie tun.

In dem Sinne SecureStringfunktioniert ziemlich einfach:

1) Alles ist verschlüsselt

2) Benutzeranrufe AppendChar

3) Entschlüsseln Sie alles in UNMANAGED MEMORY und fügen Sie den Charakter hinzu

4) Verschlüsseln Sie alles erneut in UNMANAGED MEMORY.

Was ist, wenn der Benutzer Zugriff auf Ihren Computer hat? Wäre ein Virus in der Lage, auf alle zuzugreifen SecureStrings? Ja. Alles, was Sie tun müssen, ist sich anzuschließen, RtlEncryptMemorywenn der Speicher entschlüsselt wird. Sie erhalten den Speicherort der unverschlüsselten Speicheradresse und lesen sie aus. Voila! Tatsächlich könnten Sie einen Virus erstellen, der ständig nach seiner Verwendung sucht SecureStringund alle Aktivitäten damit protokolliert. Ich sage nicht, dass es eine leichte Aufgabe sein wird, aber es kann getan werden. Wie Sie sehen können, ist die "Leistungsfähigkeit" von SecureStringvollständig verschwunden, sobald sich ein Benutzer / Virus in Ihrem System befindet.

Sie haben ein paar Punkte in Ihrem Beitrag. Sicher, wenn Sie einige der UI-Steuerelemente verwenden, die intern ein "String-Passwort" enthalten, ist die Verwendung von actual SecureStringnicht so nützlich. Trotzdem kann es vor Dummheit schützen, die ich oben aufgeführt habe.

Wie bereits erwähnt, unterstützt WPF auch PasswordBox, das SecureStringintern über seine SecurePassword- Eigenschaft verwendet wird.

Das Endergebnis ist; Wenn Sie vertrauliche Daten (Passwörter, Kreditkarten usw.) haben, verwenden Sie SecureString. Dies ist, was C # Framework folgt. In der NetworkCredentialKlasse wird beispielsweise das Kennwort als gespeichert SecureString. Wenn man sich anschaut , diese können Sie über ~ 80 verschiedene Verwendungen in .NET - Framework von sehen SecureString.

Es gibt viele Fälle, in denen Sie in einen SecureStringString konvertieren müssen , da dies von einigen APIs erwartet wird.

Das übliche Problem ist entweder:

  1. Die API ist GENERIC. Es ist nicht bekannt, dass es sensible Daten gibt.
  2. Die API weiß, dass es sich um vertrauliche Daten handelt und verwendet "Zeichenfolge" - das ist nur schlechtes Design.

Sie haben einen guten Punkt angesprochen: Was passiert, wenn auf SecureStringkonvertiert wird string? Dies kann nur aufgrund des ersten Punktes geschehen. Beispielsweise weiß die API nicht, dass es sich um vertrauliche Daten handelt. Ich persönlich habe das nicht gesehen. Das Entfernen von Zeichenfolgen aus SecureString ist nicht so einfach.

Es ist nicht einfach aus einem einfachen Grund ; Es war nie beabsichtigt, den Benutzer SecureString in einen String konvertieren zu lassen, wie Sie sagten: GC wird aktiv. Wenn Sie sehen, dass Sie das tun, müssen Sie einen Schritt zurücktreten und sich fragen: Warum mache ich das überhaupt oder brauche ich das wirklich? deswegen?

Es gibt einen interessanten Fall, den ich gesehen habe. Die WinApi-Funktion LogonUser verwendet nämlich LPTSTR als Kennwort, was bedeutet, dass Sie anrufen müssen SecureStringToGlobalAllocUnicode. Das gibt Ihnen im Grunde ein unverschlüsseltes Passwort, das sich in einem nicht verwalteten Speicher befindet. Sie müssen das loswerden, sobald Sie fertig sind:

// Marshal the SecureString to unmanaged memory.
IntPtr rawPassword = Marshal.SecureStringToGlobalAllocUnicode(password);
try
{
   //...snip...
}
finally 
{
   // Zero-out and free the unmanaged string reference.
   Marshal.ZeroFreeGlobalAllocUnicode(rawPassword);
}

Sie können die SecureStringKlasse jederzeit mit einer Erweiterungsmethode erweitern, z. B. ToEncryptedString(__SERVER__PUBLIC_KEY)mit einer stringInstanz SecureString, die mit dem öffentlichen Schlüssel des Servers verschlüsselt ist. Nur der Server kann es dann entschlüsseln. Problem gelöst: Garbage Collection sieht niemals die "ursprüngliche" Zeichenfolge, da Sie sie niemals im verwalteten Speicher verfügbar machen. Genau das wird in PSRemotingCryptoHelper( EncryptSecureStringCore(SecureString secureString)) gemacht.

Und als etwas fast Verwandtes: Mono SecureString verschlüsselt überhaupt nicht . Die Implementierung wurde auskommentiert, weil ..warte darauf .. "Es verursacht irgendwie einen Bruch des Nunit-Tests" , was zu meinem letzten Punkt führt:

SecureStringwird nicht überall unterstützt. Wenn die Plattform / Architektur nicht unterstützt wird SecureString, erhalten Sie eine Ausnahme. Es gibt eine Liste der Plattformen, die in der Dokumentation unterstützt werden.

Erti-Chris Eelmaa
quelle
Ich würde denken , SecureStringeine Menge wäre mehr sinnvoll, wenn es einen Mechanismus waren für deren einzelne Zeichen zugreifen. Die Effizienz eines solchen Mechanismus könnte verbessert werden, indem ein Strukturtyp SecureStringTempBufferohne öffentliche Mitglieder vorhanden ist, der refan die SecureStringMethode "Ein Zeichen lesen" übergeben werden könnte [wenn die Verschlüsselung / Entschlüsselung in 8-Zeichen-Blöcken verarbeitet wird, könnte eine solche Struktur Daten enthalten für 8 Zeichen und die Position des ersten dieser Zeichen innerhalb des SecureString].
Supercat
2
Ich kennzeichne dies bei jeder Quellcode-Prüfung, die ich durchführe. Es sollte auch wiederholt werden, dass, wenn Sie SecureStringes verwenden, es den ganzen Weg durch den Stapel verwendet werden muss.
Casey
1
Ich habe die Erweiterung .ToEncryptedString () implementiert, aber mithilfe eines Zertifikats. Würde es Ihnen etwas ausmachen, einen Blick darauf zu werfen und mich wissen zu lassen, wenn ich das alles falsch mache? Ich hoffe,
Sturla
@Sturla - Was ist EngineSettingsin Ihrer Erweiterungsmethode?
InteXX
15

Das sind nur wenige Probleme in Ihren Annahmen.

Erstens verfügt die SecureString-Klasse nicht über einen String-Konstruktor. Um ein Objekt zu erstellen, weisen Sie ein Objekt zu und hängen die Zeichen an.

Bei einer GUI oder einer Konsole können Sie jede gedrückte Taste ganz einfach an eine sichere Zeichenfolge übergeben.

Die Klasse ist so konzipiert, dass Sie versehentlich nicht auf den gespeicherten Wert zugreifen können. Dies bedeutet, dass Sie das stringPasswort nicht direkt von ihm erhalten können.

Um es beispielsweise zur Authentifizierung über das Web zu verwenden, müssen Sie geeignete Klassen verwenden, die auch sicher sind.

In .NET Framework gibt es einige Klassen, die SecureString verwenden können

  • Das PasswordBox-Steuerelement von WPF speichert das Kennwort intern als SecureString.
  • Die Password-Eigenschaft von System.Diagnostics.ProcessInfo ist ein SecureString.
  • Der Konstruktor für X509Certificate2 verwendet einen SecureString für das Kennwort.

(Mehr)

Zusammenfassend kann die SecureString-Klasse nützlich sein, erfordert jedoch mehr Aufmerksamkeit vom Entwickler.

All dies wird anhand von Beispielen in der MSDN-Dokumentation zu SecureString ausführlich beschrieben

Damian Leszczyński - Vash
quelle
10
Ich verstehe den vorletzten Absatz Ihrer Antwort nicht ganz. Wie würden Sie eine SecureStringüber das Netzwerk übertragen, ohne sie in eine zu serialisieren string? Ich denke, der Punkt der OP ist, dass es eine Zeit gibt, in der Sie den Wert, der sicher in a gespeichert ist, tatsächlich verwenden möchten SecureString, was bedeutet, dass Sie ihn dort rausholen müssen und er nicht mehr sicher ist. In der gesamten Framework-Klassenbibliothek gibt es praktisch keine Methoden, die a SecureStringdirekt als Eingabe akzeptieren (soweit ich sehen kann). Was bringt es also, einen Wert überhaupt in a zu halten SecureString?
stakx - nicht mehr am
@ DamianLeszczyński-Vash, ich weiß, dass SecureString keinen String-Konstruktor hat, aber mein Punkt ist, dass Sie entweder (A) einen SecureString erstellen und jedes Zeichen aus einem String anhängen oder (B) irgendwann verwenden müssen Der in SecureString als Zeichenfolge gespeicherte Wert, um ihn an eine API zu übergeben. Davon abgesehen sprechen Sie einige gute Punkte an, und ich kann sehen, wie nützlich dies in bestimmten Fällen sein kann.
Steven Jeffries
1
@stakx Sie würden es über das Netzwerk senden, indem Sie es abrufen char[]und jeweils charüber einen Socket senden - und dabei keine durch Müll sammelbaren Objekte erstellen.
user253751
Char [] ist sammelbar und veränderbar, sodass es überschrieben werden kann.
Peter Ritchie
Natürlich kann man auch leicht vergessen, dieses Array zu überschreiben. In beiden Fällen kann jede API, an die Sie die Zeichen übergeben, auch eine Kopie erstellen.
CHao
10

Ein SecureString ist nützlich, wenn:

  • Sie erstellen es Zeichen für Zeichen (z. B. aus Konsoleneingaben) oder beziehen es von einer nicht verwalteten API

  • Sie verwenden es, indem Sie es an eine nicht verwaltete API (SecureStringToBSTR) übergeben.

Wenn Sie es jemals in eine verwaltete Zeichenfolge konvertieren, haben Sie seinen Zweck verfehlt.

UPDATE als Antwort auf einen Kommentar

... oder BSTR, wie Sie erwähnen, was nicht sicherer zu sein scheint

Nach der Konvertierung in ein BSTR kann die nicht verwaltete Komponente, die das BSTR verwendet, den Speicher auf Null setzen. Nicht verwalteter Speicher ist sicherer in dem Sinne, dass er auf diese Weise zurückgesetzt werden kann.

Es gibt jedoch nur sehr wenige APIs in .NET Framework, die SecureString unterstützen. Sie können also zu Recht sagen, dass dies heute nur einen sehr begrenzten Wert hat.

Der Hauptanwendungsfall, den ich sehen würde, ist eine Clientanwendung, bei der der Benutzer einen hochsensiblen Code oder ein Kennwort eingeben muss. Die Benutzereingaben können zeichenweise verwendet werden, um einen SecureString zu erstellen. Diese können dann an eine nicht verwaltete API übergeben werden, die den BSTR, den sie nach ihrer Verwendung erhält, auf Null setzt. Ein nachfolgender Speicherauszug enthält keine vertrauliche Zeichenfolge.

In einer Serveranwendung ist schwer zu erkennen, wo dies nützlich wäre.

UPDATE 2

Ein Beispiel für eine .NET-API, die einen SecureString akzeptiert, ist dieser Konstruktor für die X509Certificate-Klasse . Wenn Sie mit ILSpy oder ähnlichem spelunkieren, werden Sie feststellen, dass der SecureString intern in einen nicht verwalteten Puffer ( Marshal.SecureStringToGlobalAllocUnicode) konvertiert wird , der dann mit ( Marshal.ZeroFreeGlobalAllocUnicode) auf Null gesetzt wird .

Joe
quelle
1
+1, aber wirst du nicht immer "seinen Zweck vereiteln"? SecureStringWas wäre ihre Verwendung , da fast keine Methode in der Framework-Klassenbibliothek eine Eingabe akzeptiert ? Sie müssten immer stringfrüher oder später zurück konvertieren (oder BSTRwie Sie bereits erwähnt haben, was nicht sicherer zu sein scheint). Warum sollte man sich überhaupt darum kümmern SecureString?
stakx - nicht mehr am
5

Microsoft empfiehlt nicht, SecureStringfür neuere Codes zu verwenden.

Aus der Dokumentation der SecureString-Klasse :

Wichtig

Wir empfehlen nicht, die SecureStringKlasse für Neuentwicklungen zu verwenden. Weitere Informationen finden Sie unter SecureStringSollte nicht verwendet werden

Welches empfiehlt:

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. auf GitHub.

SᴇM
quelle
4

Wie Sie richtig identifiziert haben, SecureStringbietet dies einen besonderen Vorteil gegenüber string: dem deterministischen Löschen. Es gibt zwei Probleme mit dieser Tatsache:

  1. Wie andere erwähnt haben und wie Sie selbst bemerkt haben, reicht dies allein nicht aus. Sie müssen sicherstellen, dass jeder Schritt des Prozesses (einschließlich Abrufen der Eingabe, Aufbau der Zeichenfolge, Verwendung, Löschen, Transport usw.) ausgeführt wird, ohne den Verwendungszweck zu beeinträchtigen SecureString. Dies bedeutet , dass man vorsichtig sein muss nie einen GC-Managed unveränderlich erstellen stringoder einen anderen Puffer, der die sensiblen Daten gespeichert werden (oder Sie den Überblick behalten, dass auch). In der Praxis ist dies nicht immer einfach zu erreichen, da viele APIs nur eine Möglichkeit bieten, damit zu arbeiten string, nicht SecureString. Und selbst wenn Sie alles richtig machen ...
  2. SecureStringschützt vor ganz bestimmten Arten von Angriffen (und für einige von ihnen ist es nicht einmal so zuverlässig). SecureStringErmöglicht es Ihnen beispielsweise, das Zeitfenster zu verkleinern, in dem ein Angreifer den Speicher Ihres Prozesses sichern und die vertraulichen Informationen erfolgreich extrahieren kann (wie Sie richtig betont haben), aber zu hoffen, dass das Fenster für den Angreifer zu klein ist Einen Schnappschuss Ihres Speichers zu machen, wird überhaupt nicht als Sicherheit angesehen.

Wann sollten Sie es verwenden? Nur wenn Sie mit etwas arbeiten, mit dem Sie SecureStringfür alle Ihre Bedürfnisse arbeiten können, und selbst dann sollten Sie sich darüber im Klaren sein, dass dies nur unter bestimmten Umständen sicher ist.

Theodoros Chatzigiannakis
quelle
2
Sie gehen davon aus, dass ein Angreifer zu einem bestimmten Zeitpunkt einen Snapshot des Speichers eines Prozesses erstellen kann. Das ist nicht unbedingt der Fall. Betrachten Sie einen Crash-Dump. Wenn der Absturz passiert ist, nachdem die Anwendung mit den vertraulichen Daten ausgeführt wurde, sollte der Absturzspeicherauszug die vertraulichen Daten nicht enthalten.
4

Der folgende Text wurde vom HP Fortify Static Code Analyzer kopiert

Zusammenfassung: Die Methode PassString () in PassGenerator.cs speichert vertrauliche Daten auf unsichere Weise (dh in Zeichenfolge), sodass die Daten durch Überprüfen des Heaps extrahiert werden können.

Erläuterung: Im Speicher gespeicherte vertrauliche Daten (wie Kennwörter, Sozialversicherungsnummern, Kreditkartennummern usw.) können verloren gehen, wenn sie in einem verwalteten String-Objekt gespeichert werden. String-Objekte sind nicht fixiert, sodass der Garbage Collector diese Objekte nach Belieben verschieben und mehrere Kopien im Speicher belassen kann. Diese Objekte sind standardmäßig nicht verschlüsselt, sodass jeder, der den Speicher des Prozesses lesen kann, den Inhalt sehen kann. Wenn der Speicher des Prozesses auf die Festplatte ausgelagert wird, wird der unverschlüsselte Inhalt der Zeichenfolge in eine Auslagerungsdatei geschrieben. Da String-Objekte unveränderlich sind, kann das Entfernen des Werts eines Strings aus dem Speicher nur vom CLR-Garbage Collector durchgeführt werden. Der Garbage Collector muss nicht ausgeführt werden, es sei denn, die CLR verfügt über wenig Arbeitsspeicher. Daher gibt es keine Garantie dafür, wann die Garbage Collection stattfinden wird.

Empfehlungen: Speichern Sie vertrauliche Daten nicht in Objekten wie Strings, sondern in einem SecureString-Objekt. Jedes Objekt speichert seinen Inhalt jederzeit in einem verschlüsselten Format im Speicher.

vikrantx
quelle
3

Ich möchte diesen Punkt ansprechen:

Wenn ein Angreifer bereits die Mittel für eine Heap - Inspektion hat, dann ist es sehr wahrscheinlich , sie entweder (A) bereits die Mittel haben , Tastenanschläge zu lesen, oder (B) , die bereits auf den Rechner haben ... So würde mit einer SecureStringverhindern , dass sie in der Einstiegs- Daten sowieso?

Ein Angreifer hat möglicherweise keinen vollständigen Zugriff auf den Computer und die Anwendung, kann jedoch über Mittel verfügen, um auf einige Teile des Arbeitsspeichers des Prozesses zuzugreifen. Dies wird normalerweise durch Fehler wie Pufferüberläufe verursacht, wenn speziell erstellte Eingaben dazu führen können, dass die Anwendung einen Teil des Speichers verfügbar macht oder überschreibt.

HeartBleed leckt Speicher

Nehmen wir zum Beispiel Heartbleed. Speziell konstruierte Anforderungen können dazu führen, dass der Code dem Angreifer zufällige Teile des Speichers des Prozesses zur Verfügung stellt. Ein Angreifer kann SSL-Zertifikate aus dem Speicher extrahieren. Er muss jedoch nur eine fehlerhafte Anforderung verwenden.

In der Welt des verwalteten Codes werden Pufferüberläufe viel seltener zu einem Problem. Und im Fall von WinForms werden Daten bereits unsicher gespeichert, und Sie können nichts dagegen tun. Dies macht den Schutz mit so SecureStringziemlich nutzlos.

Die GUI kann jedoch für die Verwendung programmiert werden SecureString, und in diesem Fall kann es sich lohnen, das Fenster der Kennwortverfügbarkeit im Speicher zu reduzieren. Beispielsweise ist PasswordBox.SecurePassword von WPF vom Typ SecureString.

Athari
quelle
Hmm, auf jeden Fall interessant zu wissen. Um ehrlich zu sein, bin ich eigentlich nicht so besorgt über die Art von Angriffen, die notwendig sind, um überhaupt ein System zu bekommen. Ich frage nur aus purer Neugier. Vielen Dank für die Information! :)
Steven Jeffries
2

Vor einiger Zeit musste ich eine AC # -Schnittstelle für ein Java-Kreditkartenzahlungs-Gateway erstellen, und man benötigte eine kompatible sichere Kommunikationsschlüsselverschlüsselung. Da die Java-Implementierung ziemlich spezifisch war und ich auf eine bestimmte Weise mit den geschützten Daten arbeiten musste.

Ich fand dieses Design recht einfach zu bedienen und einfacher als die Arbeit mit SecureString… für diejenigen, die es gerne verwenden… fühlen Sie sich frei, keine rechtlichen Einschränkungen :-). Beachten Sie, dass diese Klassen intern sind. Möglicherweise müssen Sie sie öffentlich machen.

namespace Cardinity.Infrastructure
{
    using System.Security.Cryptography;
    using System;
    enum EncryptionMethods
    {
        None=0,
        HMACSHA1,
        HMACSHA256,
        HMACSHA384,
        HMACSHA512,
        HMACMD5
    }


internal class Protected
{
    private  Byte[] salt = Guid.NewGuid().ToByteArray();

    protected byte[] Protect(byte[] data)
    {
        try
        {
            return ProtectedData.Protect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }

    protected byte[] Unprotect(byte[] data)
    {
        try
        {
            return ProtectedData.Unprotect(data, salt, DataProtectionScope.CurrentUser);
        }
        catch (CryptographicException)//no reason for hackers to know it failed
        {
#if DEBUG
            throw;
#else
            return null;
#endif
        }
    }
}


    internal class SecretKeySpec:Protected,IDisposable
    {
        readonly EncryptionMethods _method;

        private byte[] _secretKey;
        public SecretKeySpec(byte[] secretKey, EncryptionMethods encryptionMethod)
        {
            _secretKey = Protect(secretKey);
            _method = encryptionMethod;
        }

        public EncryptionMethods Method => _method;
        public byte[] SecretKey => Unprotect( _secretKey);

        public void Dispose()
        {
            if (_secretKey == null)
                return;
            //overwrite array memory
            for (int i = 0; i < _secretKey.Length; i++)
            {
                _secretKey[i] = 0;
            }

            //set-null
            _secretKey = null;
        }
        ~SecretKeySpec()
        {
            Dispose();
        }
    }

    internal class Mac : Protected,IDisposable
    {
        byte[] rawHmac;
        HMAC mac;
        public Mac(SecretKeySpec key, string data)
        {

            switch (key.Method)
            {
                case EncryptionMethods.HMACMD5:
                    mac = new HMACMD5(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA512:
                    mac = new HMACSHA512(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA384:
                    mac = new HMACSHA384(key.SecretKey);
                    break;
                case EncryptionMethods.HMACSHA256:
                    mac = new HMACSHA256(key.SecretKey);

                break;
                case EncryptionMethods.HMACSHA1:
                    mac = new HMACSHA1(key.SecretKey);
                    break;

                default:                    
                    throw new NotSupportedException("not supported HMAC");
            }
            rawHmac = Protect( mac.ComputeHash(Cardinity.ENCODING.GetBytes(data)));            

        }

        public string AsBase64()
        {
            return System.Convert.ToBase64String(Unprotect(rawHmac));
        }

        public void Dispose()
        {
            if (rawHmac != null)
            {
                //overwrite memory address
                for (int i = 0; i < rawHmac.Length; i++)
                {
                    rawHmac[i] = 0;
                }

                //release memory now
                rawHmac = null;

            }
            mac?.Dispose();
            mac = null;

        }
        ~Mac()
        {
            Dispose();
        }
    }
}
Walter Vehoeven
quelle