2008-09-29 13 views
7

Eine der Feature-Anforderungen, die ich für das Programm habe, an dem ich gerade arbeite, besteht darin, die Liste der Anmeldeinformationen zu speichern, die Benutzer eingeben, damit sie freigegeben werden können. Der spezifische Anwendungsfall, der diese Anfrage inspirierte, war die Verwendung unseres Programms in einem großen Unternehmensnetzwerk, das aus ziemlich guten LANs bestand, die durch ein flockiges WAN verbunden waren. Die Idee war, dass unser Programm nicht gegen das WAN schlägt, wenn es ausgefallen ist, und eine Konfigurationsdatei mit den streng bewachten Administrator-Anmeldeinformationen gesendet wurde. Führen Sie es in jedem LAN aus und kopieren Sie die Ergebnisse per E-Mail zurück.Speichern eines SecureString

Ja.

Mein erster Instinkt ist es, diese Anfrage zu verspotten - Passwörter speichern? wirklich? und sicherlich würde die Netzwerkabteilung des Unternehmens bevorzugen Sie zu versuchen und verkaufen, was WAN-Produkte sie haben - aber es stellt sich heraus, eine der Klassen, die ich die Anmeldeinformationen für einen SecureString verwenden, und, nun, es ist immer gut auszusehen für Wege, wie Sie den Leuten etwas Mühe ersparen können. Das brachte mich dazu, mich zu fragen:

Ist es möglich, einen verschlüsselten SecureString zu speichern, so dass ich die sensiblen Daten in einer Datei speichern und an anderer Stelle öffnen kann?

Was sind Ihre Gedanken, Stack Overflow?

+0

Wie meinst du "geteilt im Falle eines Netzwerkausfalls"? Können Sie das bitte näher ausführen? –

Antwort

5

Es gibt keine sichere Unterstützung in SecureString, es dient als Mechanismus zum Schutz einer speicherinternen verwalteten Zeichenfolge und wird nur für die Schnittstelle zu nicht verwalteten APIs verwendet. Wenn ein Kennwort in einer System.String-Instanz gespeichert wurde, ist die Sicherheit aufgrund der Art von System.String geringer. Die Existenz von Garbage Collection und Interning würde das Passwort länger als nötig im Speicher halten. Auch aufgrund der Fülle an Debugging-Tools für .NET wäre es wesentlich einfacher, durch Reflektion oder eine andere .NET-API auf den String zuzugreifen, auch ohne die längere Lebensdauer.

Wenn Sie ein Passwort auf der Festplatte speichern, ist Ihre Sicherheit ziemlich kompromittiert. Wenn jemand physischen Zugriff auf den Computer oder Remotezugriff auf Administratorebene hat, ist es am besten, wenn Sie es schwieriger, aber niemals unmöglich machen. Verwenden Sie eine Verschlüsselungs-API, speichern Sie sie an einem sicheren Ort, konfigurieren Sie Zugriffsrechte.

Abgesehen davon, Merus, würde ich vorschlagen, dass Sie versuchen, das Gesamtsystem zu verbessern, denn für einen Anwendungsfall, wie Sie beschreiben (vorausgesetzt, ich verstehe), wäre es besser, einen Hash zu speichern als die aktuelles Passwort

+1

Ich hatte gehofft, dass SecureString den Hash für mich tun würde. Ich weiß es besser, als meine eigene Hashfunktion zu rollen. – Merus

+1

In Powershell kann SecureString speichern, jede Art und Weise mit C# ?? http://stackoverflow.com/questions/11174425/how-does-one-securely-handle-passwords-in-a-custom-written-powershell-cmdlet – Kiquenet

3

Wenn Sie die verschlüsselten Bytes von SecureString speichern möchten, funktioniert das nicht - der Schlüssel für den SecureString ist an den Benutzer und den Prozess gebunden. Lesen Sie diese Bytes in einem anderen Prozess oder für einen anderen Benutzer ein, und es gibt keine Möglichkeit, die Zeichenfolge zu entschlüsseln.

1

Sie möchten vielleicht einen Blick auf die IsolatedStorageFileStream class werfen. Es gibt Möglichkeiten zum Schreiben und Speichern von Dateidaten an, auf die nur Ihre Assembly zugreifen kann.

Ich glaube nicht, dass Sie SecureString dafür verwenden können.

1

Die Secure ist nicht serialisierbar, so dass Sie es nicht nur mit einigen der gelieferten Serializer (binär, XML, etc.) speichern können

Sie können auch nicht nur zum Beispiel Zugang eine "Password" -Eigenschaft von einem securestring-Objekt, da es so etwas nicht gibt. müssen Sie Marshalling und ein wenig Klempnerarbeit dazu verwenden. Wenn Sie Benutzerdaten irgendwo speichern möchten, empfehle ich, sie selbst zu verschlüsseln, da dies die spätere Entwicklung erleichtert. Nach der Evaluierung des SecureString-Ansatzes haben wir beschlossen, etwas selbst zu implementieren, aber das sind nur meine 2 Cent.

3

Dies würde den Punkt eines SecureString vereiteln, der sich garantiert im Speicher befindet. Wenn Sie es also in einer Datei speichern, können Sie es auch als normale Zeichenfolge speichern, da es nicht mehr "sicher" ist.

4

Vielleicht möchten Sie den Passwort-Hash vergleichen.
Sie würden ein Salz aus Benutzername und wahrscheinlich eine andere Konstante, gefolgt von der Zeichenfolge haben. Dann würden Sie das an einen Hash-Algorithmus wie SHA1 * übergeben.
Zum Beispiel

using System.Security.Cryptography; 

public byte[] GetPasswordHash(string username, string password, string salt) 
{ 
    // get salted byte[] buffer, containing username, password and some (constant) salt 
    byte[] buffer; 
    using (MemoryStream stream = new MemoryStream()) 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     writer.Write(salt); 
     writer.Write(username); 
     writer.Write(password); 
     writer.Flush(); 

     buffer = stream.ToArray(); 
    } 

    // create a hash 
    SHA1 sha1 = SHA1.Create(); 
    return sha1.ComputeHash(buffer); 
} 

Dann würden Sie das Ergebnis für GetPasswordHash(username, expectedPassword, salt)-GetPasswordHash(username, givenPassword, salt) vergleichen.
Wenn Sie eine eigene Benutzerliste mit Benutzernamen und Kennwörtern implementieren, sollten Sie nur den Hash (GetPasswordHash(username, givenPassword, salt)) speichern und mit dem gespeicherten Hashwert vergleichen.

+0

manchmal das angegebene Passwort vergleichen ist nicht die Aufgabe, aber das Programm selbst wollen Passwörter verwenden, um Autorisierung in einem anderen System zu erhalten. Wie bei einem Mail-Client verwenden Sie das Passwort, um eine Autorisierung im SMTP-Server zu erhalten. Was können wir in dieser Situation tun –

+0

@Sankaran: Jeder Fall hat seine eigene Lösung. Die meisten modernen APIs akzeptieren bereits Passwort-Hashes; Einige haben API-Schlüssel, so dass Sie nicht einmal den Hash-Wert des Passworts kennen müssen. Um ältere APIs zu verwenden, die nur die direkte Verwendung des Kennworts unterstützen, bleibt Ihnen nichts anderes übrig, als das Kennwort selbst zu speichern. In diesem Fall würde ich eine Art Verschlüsselung verwenden, obwohl es ziemlich sinnlos ist. – configurator

+0

MD5 ist als Hash-Algorithmus völlig ungeeignet. Sie brauchen bcrypt oder scrypt oder _least_ sha1 (und selbst das ist nicht wirklich empfehlenswert). –

0

Wie hier angegeben, ist SecureString nicht die beste Methode in diesem Szenario zu verwenden.

Wenn ich die Notwendigkeit, Aktie die Benutzer-Anmeldeinformationen hätte, würde ich wahrscheinlich teilen sich die Benutzernamen und die gehasht + gesalzenen Passwort, so können Sie sicher sein würde und teilen nur die Darstellung eines Passworts, nicht Es ist Inhalt.

Der einfach Weg, um dies zum Beispiel ist verwenden, um die BCryt Bibliothek (where there's a .NET representation of it) und einfach den Benutzernamen und das Passwort in einer Tabellendarstellung Host bereit

geteilt werden

Dies ist, wie Sie es verwenden würde:

StringBuilder sb = new StringBuilder(); 

// run ADO.NET/Entity Framework/etc and query your DB with something like: 
"SELECT user_id, username, password FROM [TblUsers];" 

// loop through the results 

sb.AppendFormat(
     "INSERT INTO [TblSharedUsers] SELECT '{0}','{1}','{2}'",    
      dr["id"], dr["username"], 
      BCrypt.HashPassword(dr["password"], BCrypt.GenerateSalt(12)); 
     ); 

// then run sb.ToSTring() agains your db 

auf der Client-Seite können Sie ein neues erstellen AuthenticationProvider (so wird es leicht sein, zu ändern, wenn das Netzwerk nicht verfügbar ist mit IoC und DI), die von der TblSharedUsers liest und prüfen Sie das Benutzerkennwort wie

string userPassword = Request["password"]; 

"SELECT id, password FROM [TblSharedUsers] WHERE username = @usr;" 

if(BCrypt.CheckPassword(userPassword, dr["password"])) 
    // User can log in 
else 
    // Credentials are invalid 

Ich hoffe, dass dies jemand mit dem gleichen Problem hilft.

Verwandte Themen