Java- .class
Dateien können ziemlich einfach dekompiliert werden. Wie kann ich meine Datenbank schützen, wenn ich die Anmeldedaten im Code verwenden muss?
Java- .class
Dateien können ziemlich einfach dekompiliert werden. Wie kann ich meine Datenbank schützen, wenn ich die Anmeldedaten im Code verwenden muss?
Antworten:
Geben Sie niemals Passwörter fest in Ihren Code ein. Dies wurde kürzlich in den Top 25 der gefährlichsten Programmierfehler erwähnt :
Das Hardcodieren eines geheimen Kontos und eines Passworts in Ihre Software ist äußerst praktisch - für erfahrene Reverse Engineers. Wenn das Passwort für Ihre gesamte Software gleich ist, wird jeder Kunde verwundbar, wenn dieses Passwort unweigerlich bekannt wird. Und weil es fest codiert ist, ist es ein großer Schmerz, den man beheben muss.
Sie sollten Konfigurationsinformationen, einschließlich Kennwörter, in einer separaten Datei speichern, die die Anwendung beim Start liest. Dies ist der einzige wirkliche Weg, um zu verhindern, dass das Passwort infolge der Dekompilierung verloren geht (kompilieren Sie es zunächst nie in die Binärdatei).
Weitere Informationen zu diesem häufigen Fehler finden Sie im Artikel CWE-259 . Der Artikel enthält eine gründlichere Definition, Beispiele und viele andere Informationen zum Problem.
In Java ist die Verwendung der Preferences-Klasse eine der einfachsten Möglichkeiten, dies zu tun. Es dient zum Speichern aller Arten von Programmeinstellungen, von denen einige einen Benutzernamen und ein Passwort enthalten können.
import java.util.prefs.Preferences;
public class DemoApplication {
Preferences preferences =
Preferences.userNodeForPackage(DemoApplication.class);
public void setCredentials(String username, String password) {
preferences.put("db_username", username);
preferences.put("db_password", password);
}
public String getUsername() {
return preferences.get("db_username", null);
}
public String getPassword() {
return preferences.get("db_password", null);
}
// your code here
}
Im obigen Code können Sie die setCredentials
Methode aufrufen , nachdem Sie in einem Dialogfeld nach dem Benutzernamen und dem Kennwort gefragt haben. Wenn Sie eine Verbindung zur Datenbank herstellen müssen, können Sie einfach die Methoden getUsername
und getPassword
verwenden, um die gespeicherten Werte abzurufen. Die Anmeldeinformationen werden nicht fest in Ihre Binärdateien codiert, sodass die Dekompilierung kein Sicherheitsrisiko darstellt.
Wichtiger Hinweis: Die Voreinstellungsdateien sind nur XML-Dateien im Nur-Text-Format. Stellen Sie sicher, dass Sie geeignete Maßnahmen ergreifen, um zu verhindern, dass nicht autorisierte Benutzer die Rohdateien anzeigen (UNIX-Berechtigungen, Windows-Berechtigungen usw.). Zumindest unter Linux ist dies kein Problem, da beim Aufruf Preferences.userNodeForPackage
die XML-Datei im Home-Verzeichnis des aktuellen Benutzers erstellt wird, die von anderen Benutzern ohnehin nicht gelesen werden kann. In Windows kann die Situation anders sein.
Wichtigere Hinweise: In den Kommentaren dieser und anderer Antworten wurde viel darüber diskutiert, welche Architektur für diese Situation richtig ist. In der ursprünglichen Frage wird der Kontext, in dem die Anwendung verwendet wird, nicht wirklich erwähnt, daher werde ich über die beiden Situationen sprechen, die mir einfallen. Der erste Fall ist der Fall, in dem die Person, die das Programm verwendet, die Datenbankanmeldeinformationen bereits kennt (und dazu berechtigt ist). Der zweite Fall ist der Fall, in dem Sie als Entwickler versuchen, die Datenbankanmeldeinformationen vor der Person, die das Programm verwendet, geheim zu halten.
Erster Fall: Der Benutzer ist berechtigt, die Anmeldeinformationen der Datenbank zu kennen
In diesem Fall funktioniert die oben erwähnte Lösung. Die Java- Preference
Klasse speichert den Benutzernamen und das Kennwort im Klartext, die Einstellungsdatei kann jedoch nur vom autorisierten Benutzer gelesen werden. Der Benutzer kann einfach die XML-Datei mit den Einstellungen öffnen und die Anmeldeinformationen lesen. Dies ist jedoch kein Sicherheitsrisiko, da der Benutzer die Anmeldeinformationen zunächst kannte.
Zweiter Fall: Versuch, Anmeldeinformationen vor dem Benutzer zu verbergen
Dies ist der kompliziertere Fall: Der Benutzer sollte die Anmeldeinformationen nicht kennen, benötigt jedoch weiterhin Zugriff auf die Datenbank. In diesem Fall hat der Benutzer, der die Anwendung ausführt, direkten Zugriff auf die Datenbank. Dies bedeutet, dass das Programm die Anmeldeinformationen im Voraus kennen muss. Die oben erwähnte Lösung ist für diesen Fall nicht geeignet. Sie können die Anmeldeinformationen der Datenbank in einer Voreinstellungsdatei speichern, der Benutzer kann diese Datei jedoch lesen, da er der Eigentümer ist. Tatsächlich gibt es keine gute Möglichkeit, diesen Fall sicher zu verwenden.
Richtiger Fall: Verwenden einer mehrschichtigen Architektur
Der richtige Weg, dies zu tun, besteht darin, zwischen Ihrem Datenbankserver und Ihrer Clientanwendung eine mittlere Schicht zu haben, die einzelne Benutzer authentifiziert und die Ausführung einer begrenzten Anzahl von Vorgängen ermöglicht. Jeder Benutzer hätte seine eigenen Anmeldeinformationen, jedoch nicht für den Datenbankserver. Die Anmeldeinformationen würden den Zugriff auf die mittlere Schicht (die Geschäftslogikschicht) ermöglichen und wären für jeden Benutzer unterschiedlich.
Jeder Benutzer hätte seinen eigenen Benutzernamen und sein eigenes Passwort, die ohne Sicherheitsrisiko lokal in einer Einstellungsdatei gespeichert werden könnten. Dies wird als dreistufige Architektur bezeichnet (die Ebenen sind Ihr Datenbankserver, Ihr Geschäftslogikserver und Ihre Clientanwendung). Es ist komplexer, aber es ist wirklich der sicherste Weg, so etwas zu tun.
Die grundlegende Reihenfolge der Operationen lautet:
getInventoryList
.Beachten Sie, dass die Clientanwendung während des gesamten Prozesses niemals eine direkte Verbindung zur Datenbank herstellt . Die Geschäftslogikschicht empfängt eine Anforderung von einem authentifizierten Benutzer, verarbeitet die Anforderung des Clients für eine Inventarliste und führt erst dann eine SQL-Abfrage aus.
Fügen Sie das Kennwort in eine Datei ein, die von der Anwendung gelesen wird. Betten Sie NIEMALS Passwörter in eine Quelldatei ein. Zeitraum.
Ruby hat ein wenig bekanntes Modul namens DBI :: DBRC für eine solche Verwendung. Ich habe keinen Zweifel, dass Java ein Äquivalent hat. Wie auch immer, es ist nicht schwer, einen zu schreiben.
Schreiben Sie eine Webanwendung? Verwenden Sie in diesem Fall JNDI, um es extern für die Anwendung zu konfigurieren. Eine Übersicht finden Sie hier :
JNDI bietet eine einheitliche Möglichkeit für eine Anwendung, Remotedienste über das Netzwerk zu finden und darauf zuzugreifen. Der Remote-Dienst kann ein beliebiger Unternehmensdienst sein, einschließlich eines Messaging-Dienstes oder eines anwendungsspezifischen Dienstes, aber natürlich ist eine JDBC-Anwendung hauptsächlich an einem Datenbankdienst interessiert. Sobald ein DataSource-Objekt erstellt und bei einem JNDI-Namensdienst registriert wurde, kann eine Anwendung über die JNDI-API auf dieses DataSource-Objekt zugreifen, mit dem eine Verbindung zu der von ihm dargestellten Datenquelle hergestellt werden kann.
Unabhängig davon, was Sie tun, werden die vertraulichen Informationen irgendwo in einer Datei gespeichert. Ihr Ziel ist es, es so schwierig wie möglich zu machen. Wie viel davon Sie erreichen können, hängt von Ihrem Projekt, den Anforderungen und der Dicke des Portemonnaies Ihres Unternehmens ab.
Der beste Weg ist, keine Passwörter irgendwo zu speichern. Dies wird durch die Verwendung von Hash-Funktionen zum Generieren und Speichern von Passwort-Hashes erreicht:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Hash-Algorithmen sind Einwegfunktionen. Sie verwandeln jede Datenmenge in einen "Fingerabdruck" fester Länge, der nicht rückgängig gemacht werden kann. Sie haben auch die Eigenschaft, dass der resultierende Hash völlig anders ist, wenn sich die Eingabe nur um ein kleines Bit ändert (siehe das obige Beispiel). Dies ist ideal zum Schutz von Kennwörtern, da wir Kennwörter in einer Form speichern möchten, die sie auch dann schützt, wenn die Kennwortdatei selbst gefährdet ist. Gleichzeitig müssen wir jedoch in der Lage sein, die Richtigkeit des Kennworts eines Benutzers zu überprüfen.
Hinweis ohne Bezug: Wenn Sie in früheren Zeiten im Internet auf den Link "Passwort vergessen" geklickt haben, haben Websites Ihnen Ihr Nur-Text-Passwort per E-Mail gesendet. Sie haben diese wahrscheinlich irgendwo in einer Datenbank gespeichert. Wenn Hacker Zugriff auf ihre Datenbank erhielten, erhielten sie Zugriff auf alle Passwörter. Da viele Benutzer auf mehreren Websites dasselbe Kennwort verwenden würden, war dies ein großes Sicherheitsproblem. Glücklicherweise ist dies heutzutage nicht die übliche Praxis.
Nun kommt die Frage: Wie können Passwörter am besten gespeichert werden? Ich würde diese Lösung (Authentifizierungs- und Benutzerverwaltungsdienst Stormpath's) für eine verdammt ideale Lösung halten:
Offensichtlich sind Sie weder Google noch eine Bank. Dies ist also eine Overkill-Lösung für Sie. Aber dann kommt die Frage: Wie viel Sicherheit benötigt Ihr Projekt, wie viel Zeit und Geld haben Sie?
Für viele Anwendungen ist das Speichern eines fest codierten Kennworts im Code möglicherweise eine ausreichend gute Lösung, obwohl dies nicht empfohlen wird. Durch einfaches Hinzufügen einiger zusätzlicher Sicherheitsschritte aus der obigen Liste können Sie Ihre Anwendung jedoch wesentlich sicherer machen.
Nehmen wir beispielsweise an, Schritt 1 sei keine akzeptable Lösung für Ihr Projekt. Sie möchten nicht, dass Benutzer jedes Mal ein Kennwort eingeben, oder Sie möchten / müssen nicht einmal, dass Benutzer das Kennwort kennen. Trotzdem haben Sie irgendwo vertrauliche Informationen und möchten diese schützen. Sie haben eine einfache Anwendung, es gibt keinen Server zum Speichern Ihrer Dateien oder dies ist zu viel Aufwand für Ihr Projekt. Ihre Anwendung wird in Umgebungen ausgeführt, in denen es nicht möglich ist, Dateien sicher zu speichern. Dies ist einer der schlimmsten Fälle, aber mit einigen zusätzlichen Sicherheitsmaßnahmen können Sie eine viel sicherere Lösung finden. Beispielsweise können Sie die vertraulichen Informationen in einer Datei speichern und die Datei verschlüsseln. Sie können den privaten Schlüssel der Verschlüsselung im Code fest codieren lassen. Sie können den Code verschleiern, sodass es für jemanden etwas schwieriger ist, ihn zu knacken.dieser Link . (Ich möchte Sie noch einmal warnen, dass dies nicht 100% sicher ist. Ein intelligenter Hacker mit den richtigen Kenntnissen und Tools kann dies hacken. Aufgrund Ihrer Anforderungen und Bedürfnisse ist dies jedoch möglicherweise eine ausreichend gute Lösung für Sie.)
Diese Frage zeigt, wie Kennwörter und andere Daten in einer verschlüsselten Datei gespeichert werden: Java 256-Bit-AES-Kennwortbasierte Verschlüsselung
MD5 ist ein Hash-Algorithmus, kein Verschlüsselungsalgorithmus. Kurz gesagt, Sie können nicht zurückbekommen, was Sie gehasht haben. Sie können nur vergleichen. Es sollte idealerweise zum Speichern der Benutzerauthentifizierungsinformationen verwendet werden und nicht zum Benutzernamen und Kennwort der Datenbank. db Benutzername und pwd sollten verschlüsselt und in einer Konfigurationsdatei gespeichert werden, um das Mindeste zu tun.