Formulare vor POST-Angriffen schützen & MySql-Frage
Übersicht

INpacBetreff: Formulare vor POST-Angriffen schützen & MySql-Frage |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Hallo !!! ![]() Ich begebe mich momentan in die PHP- und MySQL-Tiefen! Ich lieb's! is ja so gut was man damit alles machen geht, wie schnell man zu Ergebnissen kommt (fast wie in Blitz ![]() Ich habe zwei Fragen: (1) Gegeben sei ein Useraccount-Editier-Formular, welches über POST-method Daten an eine edit.php schickt (über AJAX, sei aber mal eine Nebensache). Das Script edit.php nimmt die Post-Dateien auf, und aktualisiert die Benutzerdaten. Fein! Ich will aber für eine gewisse Sicherheit suchen. Zum einen erfolgt immer nur dann eine MySQL-Aktualisierung, wenn eine PHP-Session am laufen ist, sagen wir mal, ich nehme immer die Bedinung Code: [AUSKLAPPEN] if (isset($_SESSION['id']))
Ok! Das ist mir noch nicht genug, wer weiß wie leicht man das hacken kann! Deshalb habe ich mir gedacht, dass ich jedem Formular, welches Daten an edit.php schickt über ein input (type 'hidden') einen Sicherheitsschlüssel mitliefert, und nur wenn dieser valide ist, führt edit.php die Aktualisierung aus: Im Formular: Code: [AUSKLAPPEN] <input type="hidden" name="secure" value="<?=generate_formKey('userdaten_aendern')?> Im edit.php: Code: [AUSKLAPPEN] if (valid_formKey($_POST['secure'],'userdaten_aendern')) aendereUserDaten; ..., wobei generate_formKey() einen vom Title des Formulars abhängigen Keys generiert. Deshalb muss in edit.php diesen titel wieder angeben werden (hier: 'userdaten_aendern'). Um diesen Key nicht für jeden offen zu legen, sei er mit md5() verschlüsselt. Damit man nun nicht einfach den Key aus der HTML-Ausgabe des Browsers herausnimmt und mit ihm einen Angriff starten kann, muss dieser Key so generiert werden, dass er nicht NUR vom title des Formulars abhängt: Wie wäre es mit der aktuellen Stunde, des aktuellen Tages usw ? Bringt das was? Dann hat man immer einen anderen Key, und md5 lässt sich nicht decoden. Nur: wenn der Key vom Tag abhängt, und der User um 23:59:59 seine Daten ändern will, und der Key erst um 0:00:00 ankommt, wird seine Anfrage nicht bearbeitet, weil der Key dann abgelaufen ist. Habt ihr eine Idee, wie man einen solchen Key gestalten könnte ? Und ganz wichtig: ist damit ein guter Schutz vor Angriffen schon gegeben? (2) Thema Normalisierung von MySQL-Tabellen: Im Moment hat ein User mehrere Eigenschaften, wie Name, Email-Adresse, last-login-date, usw. alles in einer Tabelle. Was ich ausgelagert habe sind zB. die Verbindungen eines Users zu einer Benutzergruppe über die Tabelle 'connection' mit den Einträgen 'connectionID','userID','groupID'. Nun hat der Möglichkeit, Einstellungen zu speichern, zb. ob andere User Beiträge von ihm sehen dürfen: Was ist nun zu tun: eine eigene Tabelle 'setting' mit den einzelnen Optionen als Spalten-Titeln für jeden User ? Oder doch wieder einfach alles in die Haupt-User-Tabelle drunterknallen? Wie ist das mit der Harmonie zwischen MySQL und PHP: Wenn jeweils über MySQL, als auch über PHP eine Möglichkeit besteht, zu einer Ausgabe XX zu kommen. Was ist vorzuziehen? zB. bilde ich momentan teils noch PHP-Arrays mit userIDs drin, indem ich mehrere SELECT-Abfragen an SQL schicke, die fetch_rows zu dieser PHP-Array hinzufüge und damit dann umgehe. Ist es besser lieber ALLES zu erst versuchen mit den Funktionen von MySQL zu werkeln? Kann man sagen 'lieber einen Haufen an Tabellen und einen Haufen an Daten in der SQL-Datenbank, als ellenlange PHP-Operationen, wegen schlechter Normalisierung' ? Helft mir auf die Sprünge ![]() Ich würde ja gern den Haufen an tutorials durcharbeiten, aber das Studium ist sehr hart und zeitraubend ![]() Grüße aus Lautern, INpac |
||
![]() |
Thorsten |
![]() Antworten mit Zitat ![]() |
---|---|---|
Zitat: Ok! Das ist mir noch nicht genug, wer weiß wie leicht man das hacken kann!
Wie stellst du dir so einen Hackversuch vor? Zu den besagten Benutzereinstellungen : Du könntest alle Settings in einem field speichern, jedes mit einem Leerzeichen trennen, und innerhalb von PHP dann mit explode() auf einen Array aufteilen. mfG, Thorsten |
||
FWeinbehemals "ich" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Also die $_SESSION Variabeln werden ja auf dem Server gespeichert also ist es so gut wie Unmöglich da etwas zu Hacken, alles andere ist zwar gut und schön nur macht es dir die Arbeit nicht grade leichter.
Also meiner Meinung nach sind Sessions sicher, oder kannst du mir ein Beispiel zeigen wo du sie umgehen kannst. mfg ich |
||
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs |
INpac |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
@ Thorsten:
Genau das ist so ein Fall, wo ich zwei Möglichkeiten hätte: 1. MySQL: Code: [AUSKLAPPEN] $query = @mysql_query("SELECT showcomments FROM usersettings WHERE userID = '123'");
$result = @mysql_fetch_row($query); $setting_showcomments = $result[0]; 1. PHP: Code: [AUSKLAPPEN] $query = @mysql_query("SELECT settings FROM user WHERE userID = '123'");
$result = @mysql_fetch_row($query); $setting = explode(' ',$result[0]); $setting_showcomments = $setting[13]; // Sei 13 gerade die showcomments-Setting Ersteres scheint mir sehr viel eleganter und sicherlich auch schnell oder? @ich Hmm ich bin nich so de Hacker, also ich weißes nich ![]() ![]() |
||
![]() |
tedy |
![]() Antworten mit Zitat ![]() |
---|---|---|
Sessions sind keinesfalls Serverseitige Variablen :O
Sessions sind einfach nur Cookies die von php verwaltet werden |
||
01010100 01100101 01000100 01111001 00100000 00111010 01000100 |
FWeinbehemals "ich" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Also das was ich über Sessions "gelernt", wird auf dieser Seite gut zusammengefast.
http://www.php-kurs.info/tutor...okies.html Man achte auf die spalte "Speicherord" in der ersten Tabelle. mfg ich |
||
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs |
![]() |
Xaymarehemals "Cgamer" |
![]() Antworten mit Zitat ![]() |
---|---|---|
tedy du liegst falsch.
sessions werden auf dem server gespeichert. was bei dir bleibt ist lediglich die id der session. ich habe alles im alten tut von quakenet gelernt (neue)http://tut.php-quake.net/de/sessions.html (alte)wurde leider gelöscht |
||
Warbseite |
INpac |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Ok das ist schon mal ein dickes Plus! Lasst uns Sessions vernachlässigen und annehmen, dass edit auch ohne Session-Abfrage Änderungen vornehmen darf. Deshalb der secure-key. | ||
FWeinbehemals "ich" |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Warum willst du eine PHP-Datei etwas in die MySQL Datenbank eintragen lassen ohne eine Sicherheitsprüfung über eine Session Variable zu machen ?
mfg ich |
||
"Wenn die Menschen nur über das sprächen, was sie begreifen, dann würde es sehr still auf der Welt sein." Albert Einstein (1879-1955)
"If you live each day as if it was your last, someday you'll most certainly be right." Steve Jobs |
![]() |
ZaP |
![]() Antworten mit Zitat ![]() |
---|---|---|
(1) Ich glaube was du suchst ist mysql_real_escape_string() und gesalzene MD5 Verschlüsselung (salted md5). Damit stehst du eigentlich auf der Sicheren Seite. Einfach mal nach beidem Googeln.
(2) Grundsätzlich ist es einfacher mit MySQL zu arbeiten, denn die Harmonie zwischen PHP und MySQL ist schon sehr gut, weiterhin sparst du dir eine Menge Arbeit mit diversen Such- und Sortieralgorithmen, als wenn du alles in Dateien abspeicherst und "explodest". //EDIT: Arg, falsch verstanden, einfach ignorieren. |
||
Starfare: Worklog, Website (download) |
Nox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Du kannst neben einer User-ID ja auch jeden anderen Krempel in die Session schreiben, bspw. $_SESSION['isadmin']. Da Sessions tatsächlich serverseitig gesichert werden (sonst wären's ja Cookies), ist das auch überhaupt kein Problem.
Was die Validität von Formular-Daten angeht, musst du schon selbst Hand anlegen. mysql_real_escape_string() verhindert schon mal, dass jemand über einfache SQL-Injections böse Dinge anstellt. Dann musst du selbstverständlich auf Gültigkeit (sprich Vorhandensein, richtige Datentypen, Datenformat usw.) prüfen und darauf reagieren. Deine vorgeschlagene "Secure-ID" ist relativ nutzlos, da sie eben auslesbar ist. Und es gibt schließlich genügend Alternativen, die wunderbar funktionieren. |
||
![]() |
Smily |
![]() Antworten mit Zitat ![]() |
---|---|---|
php-sessions lassen sich nicht ohne weiteres "hacken" (was auch immer du damit meinst, sicherlich, dem server ein fremdes $_SESSION['id'] unterzuschieben.)
Sagen wir einfach mal, du kannst dich als kleiner benutzer eines free- oder paidhosting-anbieters auf ihre Integrität verlassen ![]() Es sei denn, du hast XSS-Lücken auf deiner seite und ein Angreifer schafft es, irgendeinem user deiner seite einen link auf eine präperierte seite unterzuschieben und so die session-id zu klauen. Dein "Sicherheitsschlüssel", bietet, wenn ich den richtig verstanden habe, auch nicht wirklich Schutz. Man ruft das formular auf und kommt so direkt daran, dann kann man einfach eigene post-daten schicken. Wichtig ist, dass du die usereingaben validierst., bzw absicherst, dass der user "erwartete" daten eingegeben hat. Einfaches beispiel: Wenn du userdaten in einen (my)sql-query übernimmst, über diese ein mysql_real_escape_string() jagen und für Usereingaben, die du direkt auf die seite ausgibts, verwendest du htmlspecialchars() (so vermeidest du die oben erwähnten XSS-Lücken) usw. Goldene Regel: Alle daten, die vom Benutzer kommen sind potentiell böse. (Also auch z.b. der User-Agent, den man gerne für Statistiken in Datenbanken einträgt) Grüße, Smily |
||
Lesestoff:
gegen Softwarepatente | Netzzensur | brain.exe | Unabhängigkeitserklärung des Internets "Wir müssen die Rechte der Andersdenkenden selbst dann beachten, wenn sie Idioten oder schädlich sind. Wir müssen aufpassen. Wachsamkeit ist der Preis der Freiheit --- Keine Zensur!" stummi.org |
- Zuletzt bearbeitet von Smily am Do, Jan 22, 2009 9:56, insgesamt 2-mal bearbeitet
![]() |
coolo |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich würde zusätzlich RegEx anraten, damit kann man schon einiges an Sicherheit gewinnen.
Außerdem würde ich schauen ob der register_globals=on ist, wenn ja würde ich ALLE Variablen am Anfang auf 0 setzen. Somit wird das Risiko nochmals verringert. |
||
http://programming-with-design.at/ <-- Der Preis ist heiß!
That's no bug, that's my project! "Eigenzitate sind nur was für Deppen" -Eigenzitat |
INpac |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Geilo ok danke erst mal für die Tipps, da scheint ja schon einiges an Sicherheit von Haus aus gewährleistet zu sein! Wie ist das mit mysql Real escape: genügt es, das nur beim userlogin einzusetzen, um vor einem "OR 1=1" geschützt zu sein?
Zum Thema Tabellendesign noch jemand ein paar Tipps ![]() |
||
![]() |
Smily |
![]() Antworten mit Zitat ![]() |
---|---|---|
mysql_real_escape überall da verwenden, wo eingaben vom user direkt in ein query übernommen werden (login, Profil editieren, etc.) | ||
Lesestoff:
gegen Softwarepatente | Netzzensur | brain.exe | Unabhängigkeitserklärung des Internets "Wir müssen die Rechte der Andersdenkenden selbst dann beachten, wenn sie Idioten oder schädlich sind. Wir müssen aufpassen. Wachsamkeit ist der Preis der Freiheit --- Keine Zensur!" stummi.org |
Nox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
INpac hat Folgendes geschrieben: Wie ist das mit mysql Real escape: genügt es, das nur beim userlogin einzusetzen, um vor einem "OR 1=1" geschützt zu sein?
Wie Smily0412 sagte: Nicht nur dort, sondern überall. Wollte nur hinzufügen, dass es ganz richtig vor Sachen wie "OR 1=1" schützt, ja. Zitat: Zum Thema Tabellendesign noch jemand ein paar Tipps
![]() Was meinst du genau? Tabellendesign im Sinne von Datenbankdesign? Und was meinst du damit, PHP einzusetzen, um Abfragen *anzupassen*? Falls du das einfache Holen von Daten meinst: da hat PHP wenig mit an der Mütze, schließlich sorgt sich die Datenbank darum. Und die Viecher sind höllisch gut optimiert, sofern du auch ein paar Regeln befolgst (Indizes, sinnvolle Feldtypen usw.). PHP bereitet die Daten dann nur für dich auf, aber das ist relativ trivial. |
||
INpac |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
hey ![]() danke! mal ein konkretes Beispiel: Ich habe eine Tabelle 'verbindungen' mit den Spalten ('verbindungs_id',) 'id1','id2', in der gespeichert wird, wenn User 1 (userID=123) mit User 2 (userID = 456) eine Verbindung herstellt: Code: [AUSKLAPPEN] "INSERT INTO verbindungen(id1,id2) VALUES($id1,$id2)"
Um zurückverfolgen zu können, welcher User die Verbindung "angefragt" hat, ist in userID1 immer die ID des Users, die die Verbindung aufbauen möchte, in UserID2 eben die "Ziel-ID" der Anfrage. Jetzt muss ich sehr oft Verbindungen einer einzigen ID ($userID) abfragen, und die jeweils mit ihr verbundene ID ($andereID) grafisch ausgeben, was momentan so gelöst ist: Code: [AUSKLAPPEN] "SELECT userID1,userID2 FROM verbindungen WHERE userID1='$userID' OR userID2='$userID' "
while($connection = mysql_fetch_row(..)) { if ($connection[0]==$userID) $andereID = $connection[1] else $andereID = $connection[0]; gebe_grafisch_aus( $andereID ); } Die if-Bedinung ist immer notwendig, um zu schauen, welche der beiden gefetchten IDs nun die gesuchte ID ist. Das wirkt auf mich ziemlich unelegant, vielleicht habe ich hier die Tabelle 'verbindungen' nicht geschickt genug designt. Oder ist das schon die beste (schnellste?) Art und Weise ? Hoffe ich habe das verständlich und nicht zu kompliziert erläutert, so ein Spezialfall von Problem. Eine Stufe höher: Es seien nicht nur User in der Lage, sich zu verknüpfen, sondern auch andere Objekte. Anhand der Länge ihrer ID ist ihre Objekt-Art eindeutig bestimmt. Eine Objekt-Art ist wiederrum durch eine Konstante bestimmt, also IDTYP_USER=1, IDTYP_KUCHEN=2,.. Wenn jetzt von einer ID1 wieder jede Verbindung wie oben grafisch ausgegeben werden soll, muss geprüft werden, welche Objekt-Art die zweite ID hat, also ob der User mit einem Kuchen, einem Keks oder einem anderen User verbunden ist. Zwei Möglichkeiten: Ich ermittle diese Objektart jedesmal über eine function get_ID_typ( $id ), die anhand der String-Länge nun die Objekt-Art zurückliefert. Oder ich erweitere die verbindungen-Tabelle ('id1','id2') mit zwei weiteren Spaltentiteln: 'IDtyp_ID1' und 'IDtyp_ID2', in denen beim erstellen einer verbindungs-Instanz einmalig die Objekt-Art gespeichert wird und später nur noch abgefragt werden muss. Was ist besser? Hier stehen sich - wie so oft - Speicherplatz und Schnelligkeit gegenüber. Das genau mein ich mit Tabellendesign und der beiseitigen Anwendung von PHP und MySQL. Hab da Schwierigkeiten zu sehen, was die beste Lösung ist! gruß |
||
#ReaperNewsposter |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Zum Thema POST:
Normal wird in dem Hidden-Field eine zufällige (längere) Nummer reingeschrieben, welche ebenfalls in der Session gespeichert wird. In der edit.php wird dann einfach verglichen. Sollte man aufjeden fall einbauen, sonst hast du eine XSS ähnliche Lücke (weiß den Namen nicht mehr). Nur ein kleines, ähnliches Beispiel mit Get: Würde ich auf meiner (nicht anwesenden Webseite) z.B. ein unsichtbares iFrame erstellen, welches auf Code: [AUSKLAPPEN] http://www.blitzforum.de/forum/login.php?logout=true verlink, würde jeder Besucher (der hier eingeloggt ist) automatisch ausgeloggt. Funktioniert so aber nicht, denn das Logout-Script will die Session-ID übermittelt bekommen. Nur mal so als harmloses Beispiel. ![]() Und da SQL-Injection ein sehr ernstes Thema ist, rate ich dir doch mal etwas zu lesen: http://de.wikipedia.org/wiki/SQL-Injection ist sehr hilfreich. ![]() |
||
AMD Athlon 64 3500+, ATI AX800 Pro/TD, 2048 MB DRR 400 von Infineon, ♥RIP♥ (2005 - Juli 2015 -> sic!)
Blitz3D, BlitzMax, MaxGUI, Monkey X; Win7 |
Nox |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
INpac hat Folgendes geschrieben: Das wirkt auf mich ziemlich unelegant, vielleicht habe ich hier die Tabelle 'verbindungen' nicht geschickt genug designt. Oder ist das schon die beste (schnellste?) Art und Weise ?
Hoffe ich habe das verständlich und nicht zu kompliziert erläutert, so ein Spezialfall von Problem. Die Verbindungen-Tabelle ist schon okay soweit, wenn auch unpraktisch. Man könnte nun hingehen und keine bi-direktionalen Verbindungen erlauben, sondern immer ein Quelle/Ziel-Tupel benutzen. Das würde bedeuten, du trägst zwei Datensätze ein, ein Mal (Quelle, Ziel) und ein Mal (Ziel, Quelle), quasi. Aber das führt halt zur Datenverdopplung und ist nicht gerade wünschenswert. ![]() Da aber SQL mehr kann als nur ein bisschen SELECT und INSERT, kann man das SQL-Statement so anpassen, dass die Daten direkt korrekt rauskommen. Beispiel: Code: [AUSKLAPPEN] $sql = 'SELECT IF( id1 = %d, id1, id2 ) selfid, IF( id2 != %d, id2, id1 ) otherid FROM link WHERE %d IN( id1, id2 ); $sql = sprintf( $sql, $wantedid, $wantedid, $wantedid ); ... Zugegeben, das sprintf() schaut mit den 3 $wantedid hässlich aus, aber es liefert dir immer die gewünschten IDs in korrekter Anordnung. Wenn du das Tupel mit mysql_fetch_assoc() holst, kannst du es bequem mit $bla['selfid'] und $bla['otherid'] auslesen. Lasse die Datenbank immer so viel wie möglich erledigen. Die ist in den meisten Fällen schneller als PHP. ![]() Zitat: Eine Stufe höher: Es seien nicht nur User in der Lage, sich zu verknüpfen, sondern auch andere Objekte. Anhand der Länge ihrer ID ist ihre Objekt-Art eindeutig bestimmt. Eine Objekt-Art ist wiederrum durch eine Konstante bestimmt, also IDTYP_USER=1, IDTYP_KUCHEN=2,..
Anhand der Länge ihrer ID? Das scheint mir falsch. Deine Datenbank ist somit nicht rational. Was ein Objekt für ein Typ ist, sollte eindeutig irgendwo hinterlegt sein, und nicht durch schwammige "Wenn die ID so-und-so lang ist, dann isses ein Keks" definiert sein. Zitat: Ich ermittle diese Objektart jedesmal über eine function get_ID_typ( $id ), die anhand der String-Länge nun die Objekt-Art zurückliefert.
Kannst du machen, aber schwammig wie oben erwähnt. ![]() Zitat: Oder ich erweitere die verbindungen-Tabelle ('id1','id2') mit zwei weiteren Spaltentiteln: 'IDtyp_ID1' und 'IDtyp_ID2', in denen beim erstellen einer verbindungs-Instanz einmalig die Objekt-Art gespeichert wird und später nur noch abgefragt werden muss.
Das ist eigentlich noch schlimmer, weil eine Verbindung zwischen zwei Tupeln nicht aussagen sollte, was die beiden für Typen sind. Hier scheint mir der Knackpunkt deines Designs zu sein. Beide IDs in der Verbindungen-Tabelle müssen sich, um die Rationalität zu erhalten, auf ein und dieselbe Tabelle beziehen -- dies wäre dann eine klassische m:n-Beziehung für die Verbindungs-Tabelle. Was hast du eigentlich ungefähr mit dieser Verbindungs-Tabelle vor? Wenn du damit alles Mögliche für alle möglichen Zwecke verbinden willst: Vergiss' es. ![]() Du willst zu einer User-ID Charaktere verwalten und zu Charakteren Inventar-Gegenstände. Da böte sich ja so eine Verbindungs-Tabelle an, die das alles zusammenfasst. Genau das ist aber falsch. Werde im Datenbankdesign möglichst konkret, soll heißen: Eine Tabelle, die User-IDs mit bestehenden Charakter-IDs verbindet und eine Tabelle, die Charakter-IDs mit bestehenden Objekt-IDs verbindet. Du wirst merken, dass das viel logischer erscheint und spätestens beim Abfragen all der Dinge wirst du froh sein, weil's die Sache erheblich erleichtert. Klar gibt das alles mehr Tabellen, als du dir vielleicht gewünscht hast, aber daran gewöhnt man sich fix. ![]() |
||
INpac |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
hey,
danke für das brainstorming. Genau das möchte ich: alles mit allem verbinden können, objektbasierten Charakter erschaffen. Für jede Art von Connection eine eigene Tabelle zu erstellen kam mir natürlich auch schon in den Sinn. Deine Bestätigung bringt mich dazu, mein System neu zu schreiben ![]() ![]() Nur: Wieder so eine Frage: wenn ich dann ALLE connections haben möchte, die mit einer ID zu tun haben: Connections von ID zu Kuchen, von ID zu Keksen, von Torten zu ID, von Rezept zu ID (also Connections wo die ID Initiator ODER target der Connection ist). Ist es dann besser fünf (Bsp-Anzahl der ID-Typen) mysql-Abfragen zu machen und die resultierenden Arrays (mit den IDs drin) mit PHP "array_merge" zu einer array zusammenzufügen, oder kann man hier auch über geschickte Anwendung von SELECT und JOIN mysql diese Arbeit überlassen (da ich denke, dass das schnellere wäre) ? gruß aus Lautern! |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group