2009-07-01 4 views
2

Ich habe eine Anwendung, die eine Verbindung zu einer Reihe von SQL Servern für Überwachung und andere Aufgaben herstellt. Derzeit unterstütze ich nur die vertrauenswürdige Authentifizierung, da ich keine sensiblen Daten speichern muss. Ich möchte die Möglichkeit hinzufügen, SQL-Authentifizierung (Benutzername/Passwort) zu verwenden.Speichern von SQL Connection-Details - wie kann ich pro Benutzer sicher verschlüsseln?

Was ist der beste Ansatz zum Speichern dieser vertraulichen Daten zwischen Sitzungen? Gibt es ein benutzerdefiniertes Zertifikat oder einen Verschlüsselungsschlüssel, den ich verwenden kann? Ist es sicher genug, einen Registrierungsschlüssel zu verwenden, der zufällig pro Benutzer generiert wird, um diese Informationen zu verschlüsseln? Wenn es einen Weg gibt, einen Schlüssel zu benutzen (oder einen zu erstellen und zu speichern), so dass kein anderer Benutzer auf dem Computer darauf zugreifen kann, ist das ideal.

Ich verstehe Verschlüsselung, also bin ich nicht auf der Suche nach einem Tutorial - Ich bin auf der Suche nach der sichersten Methode, um die Konfigurationsdaten eines Benutzers für meine Anwendung sicher vor anderen Benutzern zu halten.

Antwort

6

Verwenden Sie Data Protection API (aka. DPAPI). Jede Verwendung hat einen Schlüssel, der durch sein Passwort geschützt ist. Sie speichern das Kennwort/die Verbindungszeichenfolge in einer .config-Datei, und .NET Framework verfügt über Methoden zum Verschlüsseln/Entschlüsseln eines Konfigurationsabschnitts mit einem Computerschlüssel, einem Benutzerschlüssel oder einem RSA-Schlüssel. Erfinde das Rad nicht neu, indem du dein eigenes Schema machst. Und die Verwendung eines Registrierungsschlüssels ist definitiv eine schlechte Idee. Sicherheit kommt von Geheimnissen, nicht von Zugriffsschutz: Sie muss sich darauf verlassen, dass der Benutzer ein Geheimnis (sein Passwort bei der Anmeldung) angibt, nicht auf einem nicht zugänglichen Registrierungsschlüssel.

How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI

+0

Es scheint, dass ich die DPAPI verwenden und einen Schlüssel im Benutzerspeicher speichern kann, so dass es für andere Benutzer auf dem Computer nicht zugänglich ist. Das scheint genau das zu sein, was ich machen möchte - danke! – SqlRyan

+0

Ich endete mit einer modifizierten Version des gleichen hier: http://www.obviex.com/samples/dpapi.aspx – SqlRyan

0

Als Remus wies darauf hin, gibt es Benutzer/Maschine-Level-Verschlüsselung zur Verfügung.

Ich habe im Allgemeinen Angst vor solchen Dingen, weil diese Daten relativ leicht verloren gehen können.

Wenn ich Sie wäre, würde ich mein eigenes System rollen. Verschlüsseln Sie die Verbindungszeichenfolgen mithilfe eines in Ihrer Anwendung fest codierten Schlüssels, konvertieren Sie sie in Base64, und speichern Sie die resultierenden verschlüsselten Verbindungszeichenfolgen in der Registrierung.


Die folgende Funktion nimmt einen String, verschlüsselt sie mit AES-256 und dem angegebenen Schlüssel und base64 ist das Ergebnis so ist es wieder als druckbare string:

Probe Verbrauch:

String connectionString = EncryptString(
    "Provider=SQLOLEDB;Data Source=Lithium;User Id=sa;Password=hello", 
    "A fairly complicated password, like a guid: 8B4B0D73-84C9-4A1E-8DD2-9A189F84FD9B"); 


public static string EncryptString(string source, string key) 
{ 
    Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt); 
    byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize); 


    Rijndael rijndael = Rijndael.Create(); 

    rijndael.Mode = cipherMode; 
    rijndael.Padding = paddingMode; 
    rijndael.KeySize = keySize; 
    rijndael.BlockSize = blockSize; 
    rijndael.FeedbackSize = blockSize; // no bigger than the blocksize 

    rijndael.Key = derivedKey; 
    rijndael.IV = iv; 

    ICryptoTransform transform = rijndael.CreateEncryptor(); 

    byte[] encoded = Encoding.UTF8.GetBytes(source); 

    byte[] target = transform.TransformFinalBlock(encoded, 0, encoded.Length); 
    return Convert.ToBase64String(target); 
} 

public static string DecryptString(string source, string key) 
{ 
    Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt); 
    byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize); 

    Rijndael rijndael = Rijndael.Create(); 

    rijndael.Mode = cipherMode; 
    rijndael.Padding = paddingMode; 
    rijndael.KeySize = keySize; 
    rijndael.BlockSize = blockSize; 
    rijndael.FeedbackSize = blockSize; // no bigger than the blocksize 

    rijndael.Key = derivedKey; 
    rijndael.IV = iv; 

    ICryptoTransform transform = rijndael.CreateDecryptor(); 

    byte[] decoded = Convert.FromBase64String(source); 
    byte[] target = transform.TransformFinalBlock(decoded, 0, decoded.Length); 

    return Encoding.UTF8.GetString(target); 
} 

    private static readonly byte[] iv = { 
     0x30,0xA6,0x65,0xDE,0x8C,0x63,0x17,0x44, 
     0xB6,0xFD,0xEA,0x5F,0x76,0xA1,0x1C,0x5F 
    }; 

    private static readonly byte[] salt = { 
     0xF9,0x39,0x0C,0xE0,0x22,0xE0,0x8E,0x84, 
     0xB2,0x05,0x1E,0xA8,0x6D,0x1C,0x39,0xAC 
    }; 

    private const int keySize = 256; 
    private const int blockSize = 128; 
    private const CipherMode cipherMode = CipherMode.CBC; 
    private const PaddingMode paddingMode = PaddingMode.PKCS7; 
    private const int derivedKeySize = 32; 
1

Wie Remus sagte, verwenden Sie DPAPI. Verwenden Sie statt PInvoke-Methoden (wie in Ihrem verknüpften Beispiel) die Klasse ProtectedData. Das ist ein managed Wrapper um DPAPI. Viele der Beispiele verwenden PInvoke, um auf DPAPI zuzugreifen, da es vor .Net 2.0 keine Möglichkeit gab, dies zu tun. Mit der Klasse DataProtectionScope können Sie Daten für den aktuellen Benutzer oder Computer verschlüsseln/entschlüsseln.

+0

Notiert - Ich mag die Aufrufe auch nicht, und es ist schön zu wissen, dass es einen verwalteten Wrapper um es gibt . – SqlRyan

Verwandte Themen