Sicherheitskonzept. Bitte um eure Meinung
Thomas Grötzner
- meinung
Hallo Forum,
ich baue als Übung um in das Thema Sicherheit reinzukommen eine Web-basierte Adressverwaltung und hätte dazu gerne eure Meinung gehört.
Umfeld: Server bei Provider mit MYSQL, Perl, PHP, Linux, Apache. Als Protokoll geht leider nur http.
Ansatz:
-------
Client: JavaApplet
Server: PHP-Skript
DB dahinter: MYSQL
Applet bekommt Usereingabe
Umgekehrt beim Lesen wird Base64 dekodiert und dann wieder mit Blowfish entschlüsselt (alles im lokalen Applet).
Tabelle sieht dabei so aus:
ID (integer)
data (mediumtext)
Somit bin ich sicher vor dem lokalen Browser-Cache und die Leitung ist auch sicher und selbst wenn jemand an die DB rankommen sollte kann er die Daten zwar zerstören aber nicht lesen. Es bleibt aber ein Problem:
Auf dem Server gibt es logischerweise ein öffentliches PHP-Skript mit folgenden Funktionen:
-gib größte ID (wäre mir egal)
-gib alle Records (wäre mir egal, kann ja keiner was mit anfangen)
-füge neuen Record an (passt mir schon nicht mehr so da dies ja Schrottdaten wären)
-lösche Record mit ID (passt mir überhaupt nicht)
Einfach wäre natürlich das PHP-Skript per .htaccess zu schützen dann muss das Applet sich anmelden aber das ist natürlich wieder "unsecure" wegen dem cleartext Passwort das über die Leitung geht. Alternativ hätte ich noch die Idee:
Anmerkungen? Denkfehler? Verbesserung?
Jede Kritik und jeder Verbesserungsvorschlag sind gerne willkommen.
Ciao
Thomas Grötzner
Hi,
Umfeld: Server bei Provider mit MYSQL, Perl, PHP, Linux, Apache. Als Protokoll geht leider nur http.
Ansatz:
Client: JavaApplet
Server: PHP-Skript
Du meinst Apache mit einem PHP-Skript.
DB dahinter: MYSQL
Auf dem rechner Lokal?
Ist der MYSQL-Server und die Datenbank daraus gegen draussen abgeschotten und erlaubt nur Zugriff vom Webserver?
Bist du sicher, dass wirklich nur Port 80 offen ist?
Applet bekommt Usereingabe
- Verschlüsselung mit Blowfish
- Umwandeln in Base64 (nur zwecks einfacherem Handling wegen NULL)
- Übertragung zum Server
- Speicherung in DB
Könnte man so machen...
Umgekehrt beim Lesen wird Base64 dekodiert und dann wieder mit Blowfish entschlüsselt (alles im lokalen Applet).
Tabelle sieht dabei so aus:
ID (integer)
data (mediumtext)
Was hat die Table damit zu tun?
ich denke, das PHP-Skript decodiert und wandelt dann die Eingaberequests in entsprechende Abfragen an die datenbank um, die dann aber natürlich ganz anders aussehen können.
Somit bin ich sicher vor dem lokalen Browser-Cache und die Leitung ist auch sicher und selbst wenn jemand an die DB rankommen sollte kann er die Daten zwar zerstören aber nicht lesen. Es bleibt aber ein Problem:
Auf dem Server gibt es logischerweise ein öffentliches PHP-Skript mit folgenden Funktionen:
-gib größte ID (wäre mir egal)
wieso?
-gib alle Records (wäre mir egal, kann ja keiner was mit anfangen)
wieso?
-füge neuen Record an (passt mir schon nicht mehr so da dies ja Schrottdaten wären)
urg
-lösche Record mit ID (passt mir überhaupt nicht)
Warum kann dein PHP-Skript dies alles?
Einfach wäre natürlich das PHP-Skript per .htaccess zu schützen dann muss das Applet sich anmelden aber das ist natürlich wieder "unsecure" wegen dem cleartext Passwort das über die Leitung geht.
Du machst doch schon eine Verschluesselung.
Warum machst du dann nicht auch damit eine Identifizierung des Clients?
Du kannst entweder der Clientsoftware eine zeitabhaengige Identifation mitgeben, die eine Checksumme aus einen Private/Public-key verfahren nutzt.
Ausserdem kannst du natuerlich auch eine Usereingabe fordern.
Alternativ hätte ich noch die Idee:
- ein Client sagt zum Server erstmal HELLO
- der Server schickt eine zufällige Zeichenkette zurück und speichert sich diese mit der Session-ID in einer DB
- der Client wird diese Zeichenfolge dann mit einem Kennwort verschlüsseln (Blowfish) und zurückschicken
- Der Server führt auf seine Zeichenfolge die gleiche Verschlüsselung durch und bei Übereinstimmung wird der DB-Eintrag als "VALID" gekennzeichnet und in der DB mit einem Timestamp versehen. Bei jedem Aufruf wird dann geprüft ob die Session-ID mit einer VALID Session übereinstimmt und ob die Zeit vom letzten Zugriff nicht länger als x Minuten her ist. Falls ok wird der aktuelle Timestamp reingeschrieben. Falls nicht ok liefert das Skript nur eine Fehlermeldung als Response zurück.
Klar, kann man machen.
Aber das waere nur die eine Seite.
Du willst doch den Zugriff auf relevante Daten unterbinden.
Und nicht nur einfach die Verschluessung/Decodierung der Übertragung erschweren!
Anmerkungen? Denkfehler? Verbesserung?
Jede Kritik und jeder Verbesserungsvorschlag sind gerne willkommen.
1. Ueberleg dir ein Rollenkonzept für die Datenbank:
Lege verschiedene User an, dieauch nur verschiedene Aktionen auf
Tables machen dürfen.
Hierbei wäre auch die Überlegung angebracht ob du nicht besser
eine professionelle datenbank anstelle von MYSQL nutzt. Zum
Beispiel Firebird.
Jeder Client kann z.B. eine Userkennung haben, die übermittelt und
genutzt wird.
2. Ueberleg dir, ob die Serverkonfiguration sicher ist.
Gerade PHP ist in letzter zeit wegen Sicherheitslücken aufgefallen.
Siehe BUGTRAQ.
Ein Konzept wäre:
Client ----> Firewall -> Apache-Server -> Datenbankserver
Kostet zwar mehr, aber wenn es z.B. um schützenswerte Personendaten
handelt, wäre sowas wichtig.
Dir kann naemlich passieren, dass jemand aufgrund eines Fehlers in
ein PHP-Skript oder in PHP selbst, einfach auf den Server
reinkommt. Der kann dann alles mitverfolgen.
3. Dein Verfahren zur Austausch von Daten sollte Zeitabhaengig sein.
D.h. eine Session-ID sollte nru eine bestimmte Zeit lang gültig
sein.
4. Dein PHP-Skript tut nur dann was, wenn es eine korrekte
Identifizierung des Gegenuebers hat. Auf keinen fall soll es
irgendwelche daten rausgeben oder IDs, wenn es nicht weiss an
wem.
Ciao,
Wolfgang
Hallo Wolfgang,
Du meinst Apache mit einem PHP-Skript.
Ja!
Auf dem rechner Lokal?
Ist der MYSQL-Server und die Datenbank daraus gegen draussen abgeschotten und erlaubt nur Zugriff vom Webserver?
Bist du sicher, dass wirklich nur Port 80 offen ist?
Rechner wird von Provider gestellt. Habe keinen Einfluss drauf. Hier muss ich einfach davon ausgehen dass der seiner Pflicht entsprechend nachkommt.
Was hat die Table damit zu tun?
ich denke, das PHP-Skript decodiert und wandelt dann die Eingaberequests in entsprechende Abfragen an die datenbank um, die dann aber natürlich ganz anders aussehen können.
Nein, eben genau nicht denn dann würden ja zwischen Client und Server wieder unverschlüsselte Daten hin und her laufen. Ich verschlüssele schon direkt auf Client-Seite, übertrage verschlüsselte Daten zum Server und PHP schreibt die Daten nur noch in die DB. DB ist nach aussen nicht bekannt. Beim Lesen werden auch genauso von PHP an das Applet verschlüsselte Daten geliefert und das Applet entschlüsselt diese praktisch erst vor der Anzeige.
Auf dem Server gibt es logischerweise ein öffentliches PHP-Skript mit folgenden Funktionen:
-gib größte ID (wäre mir egal)wieso?
-gib alle Records (wäre mir egal, kann ja keiner was mit anfangen)
wieso?
-füge neuen Record an (passt mir schon nicht mehr so da dies ja Schrottdaten wären)
urg
-lösche Record mit ID (passt mir überhaupt nicht)
Warum kann dein PHP-Skript dies alles?
Wer soll das sonst können? Das Java-Applet nicht da die Datenbank ja nicht ausserhalb des Servers bekannt ist (und ich kann die auch nicht bekannt machen).
Warum machst du dann nicht auch damit eine Identifizierung des Clients?
Du kannst entweder der Clientsoftware eine zeitabhaengige Identifation mitgeben, die eine Checksumme aus einen Private/Public-key verfahren nutzt.
Ausserdem kannst du natuerlich auch eine Usereingabe fordern.
Das ist ja das was ich mit dem unten genanten Vorschlag machen will.
- Ueberleg dir ein Rollenkonzept für die Datenbank:
Lege verschiedene User an, dieauch nur verschiedene Aktionen auf
Tables machen dürfen.
Hierbei wäre auch die Überlegung angebracht ob du nicht besser
eine professionelle datenbank anstelle von MYSQL nutzt. Zum
Beispiel Firebird.
Jeder Client kann z.B. eine Userkennung haben, die übermittelt und
genutzt wird.
Single User, nur ich. Andere Datenbank kommt nicht in Frage. Ich habe einen Provider dem ich ein paar Cent pro Monat zahle und versuche das zu machen was da geht (ist ja wie geschrieben ein Lernprojekt um mich mit Sicherheit zu beschäftigen).
Ein Konzept wäre:
Client ----> Firewall -> Apache-Server -> Datenbankserver
Kostet zwar mehr, aber wenn es z.B. um schützenswerte Personendaten handelt, wäre sowas wichtig.
Deshalb will ich ja dass ausserhalb des Clients (also sowohl auf der Leitung als auch auf dem Server) immer nur verschlüsselte Daten sind (was ja auch der Fall ist).
- Dein Verfahren zur Austausch von Daten sollte Zeitabhaengig sein.
D.h. eine Session-ID sollte nru eine bestimmte Zeit lang gültig
sein.
Beschreib ich ja mit meinem Hello Server => Server speichert SessionID + Timestamp und prüft beim nächsten Zugriff ob Timestamp nicht zu alt ist.
- Dein PHP-Skript tut nur dann was, wenn es eine korrekte
Identifizierung des Gegenuebers hat. Auf keinen fall soll es
irgendwelche daten rausgeben oder IDs, wenn es nicht weiss an
wem.
Ich glaub ich implementier das jetzt mal so wie ich mir das denke und poste dann hier einen Link zum Probieren und auch zum Sourcecode von dem Ganzen. Dann lässt es sich vermutlich leider diskutieren.
Danke Dir für Deine Vorschläge. Bei dem "Zeitabhaengig" war ich mir nicht sicher ob das wirklich notwendig ist aber da Du das genauso siehst mach ich das so.
Ciao
Thomas Grötzner
Hi Thomas,
Bist du sicher, dass wirklich nur Port 80 offen ist?
Rechner wird von Provider gestellt. Habe keinen Einfluss drauf. Hier muss ich einfach davon ausgehen dass der seiner Pflicht entsprechend nachkommt.
was ist mit anderen Ports - beispielsweise 443?
Dein Applet kann ein beliebiges proprietäres Protokoll Deiner Wahl verwenden, solange Du einen freien Port mit einem dort lauschenden daemon hast.
Viele Grüße
Michael
Hallo Michael,
was ist mit anderen Ports - beispielsweise 443?
Dein Applet kann ein beliebiges proprietäres Protokoll Deiner Wahl verwenden, solange Du einen freien Port mit einem dort lauschenden daemon hast.
Ich habe keine Ahnung ob und was für Ports auf diesem Server sind und möchte mich auf Grund der Portabilität auch nicht auf ein nicht-standard-protokoll einlassen. Wenn ich die Anwendung mal von einem Provider zum nächsten umziehe kann ich eigentlich nur sicher sein wieder http: (und natürlich php, mysql) zu haben.
Ciao
Thomas Grötzner
Hallo,
Bist du sicher, dass wirklich nur Port 80 offen ist?
Rechner wird von Provider gestellt. Habe keinen Einfluss drauf. Hier muss ich einfach davon ausgehen dass der seiner Pflicht entsprechend nachkommt.
Das lässt sich durch einen lächerlich kleinen Java Port-Scanner wie dem folgenden leicht herausfinden:
import java.net.*;
import java.io.*;
class portScanner {
static Socket portSo;
public static void scan() {
for(int i = 1; i <= 1000; i++) {
try {
// Hier die IP des Rechners eingeben
portSo = new Socket("127.0.0.1", i);
System.out.println("Port " + i + " ist offen. :-)");
portSo.close();
} catch(IOException ioe) {
System.out.println("Port " + i + " ist nicht offen.");
}
}
}
public static void main(String args[]) {
scan();
}
}
Gruß,
MI
Hallo Thomas,
SSL kannst Du nicht verwenden? Ein Schwachpunkt ist nämlich schon, dass das Applet nicht vor manipulation geschützt ist. Schließlich könnte man das Applet wärend der Übertragung manipulieren und einen Mechanismus einbauen, um das Passwort abzufangen. Schützen kannst Du Dich davor nur, indem Du SSL mit einem offiziellen Zertifikat vermendest oder das Applet mit einem solchen Zertifikat signierst.
- ein Client sagt zum Server erstmal HELLO
- der Server schickt eine zufällige Zeichenkette zurück und speichert sich diese mit der Session-ID in einer DB
- der Client wird diese Zeichenfolge dann mit einem Kennwort verschlüsseln (Blowfish) und zurückschicken
Ein Angreifer kennt also den Klartext und die verschlüsselte Nachricht. Bist Du sicher, dass sie damit nicht der Schlüssel (in diesem Fall also das Passwort) berechnen lässt?
Besser geeignet wäre in dem Fall wohl ein Hashingverfahren wie md5. Der Client könnte sich mit md5(sessionid_vom_server + md5(passwort)) anmelden. Damit würde es auch reichen, auf dem Server md5-Prüfsummen der Passwörter zu speichern.
Evt statt die Prüfsumme aus Passwort und einem zusätzlichen Datum (Benutzername, Zufallsstring, ...) damit man keine doppelten Passwörter erkennen kann und Tabellen der md5-Summen häufiger Passwörter nutzlos sind.
Grüße
Daniel
Hallo Daniel,
SSL kannst Du nicht verwenden? Ein Schwachpunkt ist nämlich schon, dass das Applet nicht vor manipulation geschützt ist. Schließlich könnte man das Applet wärend der Übertragung manipulieren und einen Mechanismus einbauen, um das Passwort abzufangen. Schützen kannst Du Dich davor nur, indem Du SSL mit einem offiziellen Zertifikat vermendest oder das Applet mit einem solchen Zertifikat signierst.
Da solch ein Zertifikat richtig viel Geld kostet kommt das natürlich nicht in Frage. Zur Manipulation des jars: das wäre aber schon recht heftig, oder? Dass das Jar-File beim Provider sicher (also nicht veränderbar) liegt davon muss ich ausgehen. Jetzt müsste jemand also dieses Jar-File nehmen, modifizieren und wenn ich dann mein Jar-File anfordere müsste mir stattdessen das manipulierte geliefert werden. Dieses müsste dann mein Passwort an einen Server senden (erlaubt ist hier ja zwecks der Sandbox nur der Server von dem das Applet kommt).
Wenn dass die Sicherheitslücke ist dann kann ich glaube ich damit leben. Was ich nicht will ist dass mit einem einfachen http-Sniffer Klartext-Kennwörter ausgelesen werden können.
Besser geeignet wäre in dem Fall wohl ein Hashingverfahren wie md5. Der Client könnte sich mit md5(sessionid_vom_server + md5(passwort)) anmelden. Damit würde es auch reichen, auf dem Server md5-Prüfsummen der Passwörter zu speichern.
Evt statt die Prüfsumme aus Passwort und einem zusätzlichen Datum (Benutzername, Zufallsstring, ...) damit man keine doppelten Passwörter erkennen kann und Tabellen der md5-Summen häufiger Passwörter nutzlos sind.
Plan ist / war: Server liefert Session-ID, die wird mit Passwort und Algorithmus verschlüsselt und zurückgeschickt. Server führt auf seiner Session-id die gleiche Verschlüsselung mit dem gleichen Passwort (das nicht mit übermittelt wurde!!!) aus und vergleicht dies.
Das mit dem One-Way-Verschlüsseln läuchtet ein. Beim Two-Way (Blowfish) hast Du natürlich recht dass jemand der mitlauscht den Klartext bekommt und anschließend die Verschlüsselung. Ob man daraus das Kennwort kriegen kann weiss ich nicht aber es ist schätzungsweise einfacher als mit dem One-Way-Verfahren. Da werde ich mal schauen welche Algor. ich sowohl für Java als auch für PHP frei bekomme.
Ciao
Thomas Grötzner
Hallo Thomas,
Da solch ein Zertifikat richtig viel Geld kostet kommt das natürlich nicht in Frage.
Ja, das ist der Hacken an dieser Technik.
Zur Manipulation des jars: das wäre aber schon recht heftig, oder?
Ja heftig schon. Den Datenstrom zu manipulieren ist natürlich wesentlich schwieriger, als ihn nur abzuhören. Ich weiß ja nicht, wie wichtig Deine Daten sind.
Dieses müsste dann mein Passwort an einen Server senden (erlaubt ist hier ja zwecks der Sandbox nur der Server von dem das Applet kommt).
Naja es würde auch reichen, wenn es das Passwort im Klartext wieder an Deinen Server schickt. Dann kann man es ja wieder abhören.
Grüße
Daniel
Hi Thomas,
Da solch ein Zertifikat richtig viel Geld kostet
das kommt darauf an, wo man es kauft. Marktführer sind in der Tat teuer.
Viele Grüße
Michael