Laden...

Datenbank verschlüsseln und Passwort beim Start eingeben

Erstellt von Plunder vor 9 Jahren Letzter Beitrag vor 9 Jahren 4.286 Views
P
Plunder Themenstarter:in
3 Beiträge seit 2014
vor 9 Jahren
Datenbank verschlüsseln und Passwort beim Start eingeben

Hallo,

ich programmiere gerade mit Visual Studio 2012 Prof eine Windows Forms Application (.NET Framework 4) mit einer MS SQL Server Compact 4.0 Datenbank, die ich gerne verschlüsseln würde. Die Datenbank soll später bei Programmstart durch Eingabe des richtigen Passwortes für die Dauer der Laufzeit entschlüsselt werden. Das Passwort soll später auch mal aus dem Programm heraus änderbar sein. Die DB in Visual Studio zu verschlüsseln und den ConnectionString in der app.config statisch anzupassen ist ja kein Problem, aber wie kann ich das via PasswordBox abgefragte Passwort dynamisch in den ConnectionString einfließen lassen, so dass ich kein Passwort mehr in der app.config benötige?

Mir ist der korrekte Ablauf insgesamt auch noch nicht ganz klar...zur Zeit rufe ich in der main() zunächst die Form für den LogIn auf, in der eine Textbox mit der Eigenschaft UseSystemPasswordChar=True vorhanden ist. Die Eingabe triggert ein Ereignis, in dem ich zur Zeit lediglich das eingegebene Passwort in eine Variable packe und anschließend eine Instanz meiner Hauptprogramm-Form erzeuge und anzeige. Bevor ich die Hauptprogramm-Form mit den Datenquellen anzeige, müsste ich ja den "EmployeeConnectionString" aktualisieren, damit Daten aus der DB ausgelesen und angezeigt werden können. Ist das so sinnvoll bzw. sicher und wenn ja, wie bekomme ich das mit dem Aktualisieren des ConnectionStrings hin?

app.config(zur Zeit noch mit Passwort):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
    </configSections>
    <connectionStrings>
        <add name="LocalDatabaseApp.Properties.Settings.EmployeeConnectionString"
            connectionString="Data Source=|DataDirectory|\Employee.sdf;Password=password;Persist Security Info=False;"
            providerName="Microsoft.SqlServerCe.Client.4.0" />
    </connectionStrings>
</configuration>

Viele Grüße,
Plunder

16.834 Beiträge seit 2008
vor 9 Jahren
P
Plunder Themenstarter:in
3 Beiträge seit 2014
vor 9 Jahren

Hallo Abt,

vielen Dank für Deine Hilfe, ich habe das mal wie folgt probiert:

           var conString = @"Data Source=|DataDirectory|\Employee.sdf;Password=" + textBox1.Text + ";Persist Security Info=False";
           var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
           var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
           connectionStringsSection.ConnectionStrings["LocalDatabaseApp.Properties.Settings.EmployeeConnectionString"].ConnectionString = conString;
           config.Save();
           ConfigurationManager.RefreshSection("connectionStrings");
           Form NewForm1 = new Form1();
           NewForm1.Show();
           this.Hide();

Das funktioniert soweit, aber jetzt habe ich noch das Problem mit der Falsch-Eingabe des Passwortes. Wenn man das falsche Passwort eingibt, öffnet sich die Form OHNE Daten, gibt man das richtige ein, öffnet sich die Form MIT Daten. RefreshSection() ist ja eine Void-Methode, .open() anscheinend auch...die sagen mir dann ja nicht, ob bzw. was falsch gelaufen ist.
Muss man das Passwort als Hash + Benutzername z.B. in einer 2. DB speichern und prüfen, bevor man die Konfiguration überschreibt und die Form lädt, oder gibt es da eine einfacherere Methode?

EDIT: Autsch! Ich glaube, bei dieser Methode wird immer das zuletzt eingegebene Passwort dauerhaft in die Konfigurations-Datei im Anwendungs-Verzeichnis gespeichert. Klar, .Save() deutet das ja auch schon an...also wohl doch keine Lösung!

Viele Grüße,
Plunder

16.834 Beiträge seit 2008
vor 9 Jahren

Hab dir den zweiten Link nicht umsonst gegeben...

die Form-Logik ist ein anderes Thema, das Dir hier aber keine abnehmen kann.
Wie man darauf reagiert, wenn das Passwort falsch ist; das wirste ja wohl hin bekommen 😉

P
Plunder Themenstarter:in
3 Beiträge seit 2014
vor 9 Jahren

Hallo Abt,

ich habe mir Deinen zweiten Link([FAQ] DB-Password/Kennwort/Connection-String sicher speichern) auch durchgelesen, aber irgendwie kann ich den entscheidenden Hinweis nicht herausfiltern. Der Einleitungs-Satz beschreibt ja auch eigentlich ein Szenario, bei dem das Programm selbst die Entschlüsselung vornimmt, also ohne Mitwirken des Nutzers und mit einem fest hinterlegten Schlüssel.
Dann folgt ein Link auf eine Diskussion, in der empfohlen wird, mit ADS/Windows-Benutzer zu arbeiten.
Darunter gibt es noch einen Link, der sich damit befasst, dass Nutzer das Datenbank-Passwort nicht herausfinden sollen, also quasi das gleiche wie im ersten Link. OK, in einem Beitrag von Lars Schmitt wird das Verschlüsseln und Entschlüsseln von Konfigurations-Abschnitten angesprochen, allerdings zielt das ja wieder auf das statische Hinterlegen von Secrets im Code ab und scheint sich zudem auch auf ASP.NET und Web-Config zu beziehen.

Darunter ist dann noch ein Beitrag von Dir, der eine Neuerung bei .NET 4.5 verlinkt, mit der man Anmelde-Informationen außerhalb des ConnectionStrings verwalten und für das Öffnen von DB-Verbindungen nutzen kann. Hier sehe ich jetzt auch keinen direkten Bezug zu meiner Frage, da ich die SQLCompact-Variante nutze und dort keine derartige Property finden konnte(oder übersehen habe). Zudem fehlt hier dann ja immer noch das entscheidende Puzzle-Teil: Wie sage ich Visual Studio, dass es die bequem zusammengeklickten Tables und DataSets NICHT mit den in der app.config Hart-Kodierten Informationen öffnen soll? In den DataSets finde ich etliche Stellen, wo der Name meines ConnectionStrings hinterlegt ist.

Insgesamt frage ich mich, nachdem ich das komplette Wochenende erfolglos mit Googlen und Lesen von englischen Texten verbracht habe, was sich Microsoft dabei gedacht hat, eine Verschlüsselung für Compact-DBs anzubieten und es mir dann so verdammt schwer zu machen, die Entschlüsselung erst nach Eingabe eines Passwortes vorzunehmen...es geht mir ja im Wesentlichen darum, von DataSets und ähnlichem profitieren zu können, aber dafür nicht die Sicherheit von AES durch irgendwelche Konfigurations-Dateien zu unterwandern. Irgendwie weiß ich immer noch nicht, ob es jetzt eine total einfache Lösung für mein Problem gibt, oder ob mein Wunsch per Design nicht vorgesehen wurde und ich daher besser beraten wäre, einfach auf DataSets zu verzichten, die DB-Connections selbst herzustellen, mit klassischen SQL-Kommandos die Daten auszulesen und die entsprechenden Controls per Hand zu befüllen(so wie früher). Da wäre ich wahrscheinlich schon fertig mit meinem Programm, aber ich wollte einfach mal den von Microsoft angedachten Weg gehen, der einem ja eigentlich so viel Arbeit abnehmen soll.

Ich wäre Dir dankbar, wenn Du mir den richtigen Weg weisen könntest.

Sorry für den vielen Text.

Viele Grüße,
Plunder

194 Beiträge seit 2006
vor 9 Jahren

Hallo
Ist schon ein Bisschen her aber meines Wissens werden TableAdapter sowie TableAdapterManger - Klassen als

partial

angelegt, daher kann man dann so programmieren:



namespace WeineApp.deinDataSetTableAdapters {
        
    public partial class TableAdapterManager
    {
        public void SetConnection(IDbConnection con)
        {
            this.Connection = con;
        }
    }

}

Gruss

16.834 Beiträge seit 2008
vor 9 Jahren

Wenn das Passwort initial eingegeben muss und ohnehin nirgends im Klartext stehen darf, dann musst Du - wie erwähnt - den Connection String von Hand zusammen bauen.
Der Connection String wird auch danach nirgens gespeichert. Hab ich auch so nicht gesagt 😉
Du musst den jedes mal zusammen bauen. Jedes mal.

Was bei der Eingabe eines falschen Passowrtes passieren soll; das ist Dein Ding.
Wenn das Passwort korrekt ist, dann willst Du es speichern - nur das Passwort; und da ist die App.Config die falsche Adresse, denn auf diese hast Du, wenn die Anwendung installiert ist, keinen Schreibzugriff mehr, da unter ProgramFiles.
Nimm die Registry, nimm eine verschlüsselte XML im Benutzerverzeichnis (ProgramData) oder ganz einfach das Konfigurationsmodell von .NET mit einem entsprechendem UserScope ([Tutorial] Konfigurationsmodell im .NET Framework).

Denk auch dran, das Passwort zu salzen (siehe Wiki: Salting).

Den Connection String anschließend in der App.Config zu speichern ist unnötig und später wie so gar nicht möglich. Du hast als normaler Benutzer keine Schreibrechte auf das Verzeichnis, wo die Config liegt.

Der Code, den Du dort oben zeigst; damit kann man nichts anfangen.

Ob Web.Config oder App.Config ist völlig egal, da nahezu der identische Mechanismus dahinter steckt.
Mach es einfach, wie ich es vorgeschlagen habe. Das funktioniert.