Codieren Sie niemals Passwörter fest in Ihren Code. Dies wurde kürzlich in den Top 25 Most Dangerous Programming Mistakes
Ein geheimes Konto und Passwort fest in Ihre Software zu codieren ist äußerst praktisch – für erfahrene Reverse Engineers. Wenn das Passwort für Ihre gesamte Software dasselbe ist, wird jeder Kunde angreifbar, wenn dieses Passwort unweigerlich bekannt wird. Und weil es hartcodiert ist, ist es sehr mühsam, es zu beheben.
Sie sollten Konfigurationsinformationen, einschließlich Kennwörter, in einer separaten Datei speichern, die die Anwendung beim Start liest. Das ist der einzige wirkliche Weg, um zu verhindern, dass das Passwort als Ergebnis der Dekompilierung preisgegeben wird (kompilieren Sie es niemals von Anfang an in die Binärdatei).
Weitere Informationen zu diesem häufigen Fehler finden Sie im CWE-259-Artikel . Der Artikel enthält eine gründlichere Definition, Beispiele und viele andere Informationen über das Problem.
In Java ist die Verwendung der Preferences-Klasse eine der einfachsten Möglichkeiten, dies zu tun. Es wurde entwickelt, um alle Arten von Programmeinstellungen zu speichern, von denen einige einen Benutzernamen und ein Passwort enthalten könnten.
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önnten Sie setCredentials
aufrufen -Methode, nachdem Sie einen Dialog mit der Frage nach Benutzername und Passwort angezeigt haben. Wenn Sie sich mit der Datenbank verbinden müssen, können Sie einfach den getUsername
verwenden und getPassword
Methoden zum Abrufen der gespeicherten Werte. Die Anmeldeinformationen werden nicht fest in Ihre Binärdateien codiert, sodass die Dekompilierung kein Sicherheitsrisiko darstellt.
Wichtiger Hinweis: Die Einstellungsdateien sind nur reine Text-XML-Dateien. Stellen Sie sicher, dass Sie geeignete Maßnahmen ergreifen, um zu verhindern, dass unbefugte Benutzer die Rohdateien anzeigen (UNIX-Berechtigungen, Windows-Berechtigungen usw.). Zumindest unter Linux ist dies kein Problem, da der Aufruf von Preferences.userNodeForPackage
erstellt die XML-Datei im Home-Verzeichnis des aktuellen Benutzers, das von anderen Benutzern ohnehin nicht gelesen werden kann. Unter Windows kann die Situation anders sein.
Weitere wichtige Hinweise: In den Kommentaren zu dieser Antwort und anderen wurde viel darüber diskutiert, was die richtige Architektur für diese Situation ist. Die ursprüngliche Frage erwähnt nicht wirklich den Kontext, in dem die Anwendung verwendet wird, also werde ich über die zwei Situationen sprechen, die mir einfallen. Der erste ist der Fall, in dem die Person, die das Programm verwendet, die Datenbankanmeldeinformationen bereits kennt (und berechtigt ist, sie zu kennen). Der zweite ist der Fall, in dem Sie als Entwickler versuchen, die Datenbankanmeldeinformationen vor der Person, die das Programm verwendet, geheim zu halten.
Erster Fall:Benutzer ist berechtigt, die Anmeldeinformationen für die Datenbank zu kennen
In diesem Fall funktioniert die oben erwähnte Lösung. Die Java Preference
class speichert den Benutzernamen und das Passwort im Klartext, aber die Einstellungsdatei ist nur für den autorisierten Benutzer lesbar. Der Benutzer kann einfach die XML-Einstellungsdatei öffnen und die Anmeldeinformationen lesen, aber das ist kein Sicherheitsrisiko, da der Benutzer die Anmeldeinformationen von Anfang an kannte.
Zweiter Fall:Versuch, Anmeldeinformationen vor dem Benutzer zu verbergen
Dies ist der kompliziertere Fall:Der Benutzer sollte die Anmeldedaten nicht kennen, benötigt aber dennoch Zugriff auf die Datenbank. In diesem Fall hat der Benutzer, der die Anwendung ausführt, direkten Zugriff auf die Datenbank, was 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 für die Datenbank in einer Einstellungsdatei speichern, aber der Benutzer kann diese Datei lesen, da er der Eigentümer ist. Tatsächlich gibt es wirklich keine gute Möglichkeit, diesen Fall auf sichere Weise zu verwenden.
Korrekter Fall:Verwendung einer mehrschichtigen Architektur
Der richtige Weg, dies zu tun, besteht darin, eine mittlere Schicht zwischen Ihrem Datenbankserver und Ihrer Clientanwendung zu haben, die einzelne Benutzer authentifiziert und die Ausführung einer begrenzten Anzahl von Operationen ermöglicht. Jeder Benutzer hätte seine eigenen Anmeldeinformationen, aber nicht für den Datenbankserver. Die Anmeldeinformationen würden den Zugriff auf die mittlere Ebene (die Ebene der Geschäftslogik) 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 dreischichtige Architektur bezeichnet (Die Schichten 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 ist:
- Der Client authentifiziert sich mit der Geschäftslogikebene unter Verwendung des persönlichen Benutzernamens/Passworts des Benutzers. Der Benutzername und das Passwort sind dem Benutzer bekannt und stehen in keinem Zusammenhang mit den Zugangsdaten für die Datenbank.
- Wenn die Authentifizierung erfolgreich ist, stellt der Client eine Anfrage an die Geschäftslogikebene und fragt nach einigen Informationen aus der Datenbank. Zum Beispiel ein Warenbestand. Beachten Sie, dass die Anfrage des Clients keine SQL-Abfrage ist; es ist ein entfernter Prozeduraufruf wie
getInventoryList
. - Die Geschäftslogikebene stellt eine Verbindung zur Datenbank her und ruft die angeforderten Informationen ab. Die Geschäftslogikebene ist dafür verantwortlich, eine sichere SQL-Abfrage basierend auf der Anforderung des Benutzers zu erstellen. Alle Parameter der SQL-Abfrage sollten bereinigt werden, um SQL-Injection-Angriffe zu verhindern.
- Die Geschäftslogikschicht sendet die Bestandsliste zurück an die Clientanwendung.
- Der Client zeigt dem Benutzer die Bestandsliste an.
Beachten Sie, dass während des gesamten Prozesses die Client-Anwendung niemals eine direkte Verbindung zur Datenbank herstellt . Die Geschäftslogikebene empfängt eine Anfrage von einem authentifizierten Benutzer, verarbeitet die Anfrage des Clients nach einer Bestandsliste und führt erst dann eine SQL-Abfrage aus.