• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

Wie übergebe ich Formulardaten sicher an eine Datenbank und lese sie wieder aus?

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
Wie in diesem Thread geschrieben habe ich mir ein tolles CSS-Formular gebastelt.

Nun würde ich gerne den nächsten Schritt gehen und die Daten an eine Datenbank schicken. Das aber so manipulationssicher wie möglich. Wenn man im Internet so sucht stößt man schnell auf eine Reihe von Befehlen, aber mir wurde nie so wirklich klar, wann welcher Befehl nun der Richtige ist und welche zwar erwähnt, aber von der Sache her unwichtig / in anderen bereits eingefasst sind.

Den Befehl mysql_real_escape_string kennt wohl jeder, scheint mir aber nur der Anfang zu sein. Jemand sagte mir mal, dass man die Variablen vorher in einen string umwandeln sollte, also $_POST['irgendwas'] = string($_POST['irgendwas']) bevor sie in den Datenbankstring wandern. Ich habe keine Ahnung was das bewirken soll. Ich habe gestern noch eine Seite gefunden, wo man mit Angriffsszenarios und was man alles dagegen machen kann regelrecht erschlagen wird, kann sie aber jetzt nicht mehr finden.

Außerdem bin ich auf dieser Seite über ein Tool gestolpert, dass Scripte wohl automatisiert auf Schwachstellen prüfen können soll. Kennt jemand dieses Tool und ist es vertrauenswürdig, bzw. taugt es was?

Beim Auslesen wird die Situation nicht besser. Als erstes kenne ich htmlspecialchars. Es gibt da aber noch eine "Abwandlung" von, nennt sich htmlentities die wohl etwas aggressiver vorgeht. Wann ist der Einsatz welches Befehls gegeben und was muss noch alles beachtet werden?

Ein Angriffsszenario welches ich kenne besteht darin, dass man beispielsweise eigene Werte in ein Auswahlfeld einschleust. Wie unterbindet man sowas beispielsweise? Welche Befehle sind für ein sicheres Formular noch von Relevanz und welche kann man eigentlich vergessen, bzw. spielen nur in bestimmten Situationen (Mail / File-Upload) eine Rolle?
 
Zuletzt bearbeitet:

keksautomat

Neu angemeldet

Registriert
15 Juli 2013
Beiträge
471
Das Thema wurde über die letzten 10 Jahre, gerade im Umgang mit PHP, so oft durchkaut, ich denke da lassen sich gute Papers finden.
Ansonsten: Tokens benutzten bei der Form, sodass nicht (ausversehen selbstverständlich) zwei Mal Daten in die DB gelangen, jeden "Mist" abfangen. (Bei einer Telefonnr erwartest du keine Zeichen und so weiter)

Befehle alá "*_real_escape*" alleine zu benutzen bringt rein gar nichts, man muss sich schon mit dem Thema "dahinter" ein wenig auseinander setzen.
Nur den Befehl da irgendwo unterzubringen bringt nur minimal was.

Gruß
 

epiphora

aus Plastik
Veteran

Registriert
14 Juli 2013
Beiträge
3.894
Ort
DE-CIX
Das, was Keksautomat sagt. Unüberdachte PHP-Programmierung führt leider schnell zu SQL-Injection-Lücken und irgendwie lädt PHP auch ein bisschen dazu ein, weil es so schlecht strukturiert ist. Daher solltest Du zur Kommunikation mit der Datenbank eine fertige Bibliothek nutzen, wie etwa PDO oder meinetwegen auch MySQLi.

Ein weiterer Tipp zur sicheren Datenübertragung wäre es, HTTPS zu nutzen.

Jemand sagte mir mal, dass man die Variablen vorher in einen string umwandeln sollte, also $_POST['irgendwas'] = string($_POST['irgendwas']) bevor sie in den Datenbankstring wandern. Ich habe keine Ahnung was das bewirken soll.
Rein gar nichts, denn die Daten sind ja bereits als String vorhanden. Höchstens andersrum würde es unter bestimmten Umständen Sinn machen: Wenn Du weißt, dass es sich bei einer bestimmten Eingabe immer um eine Zahl handelt, kannst Du sie einfach als int casten und könntest die Zahl ungefiltert in Deinen Query einbauen, ohne dass SQL-Injections möglich wären. Da Du aber ohnehin besser eine fertige Bibliothek nutzt, die Prepared Statements unterstützt, spielt das keine Rolle mehr.
 

accC

gesperrt

Registriert
14 Juli 2013
Beiträge
5.250
_real_escape_string bringt a. nur bedingt etwas und b. sichert es nur gegenüber deiner Datenbank ab. Sobald du die Daten wieder aus der Datenbank ausliest, solltest du darauf achten, dass sie im Kontext deiner Seite wiederum korrekt ausgegeben werden:


[src=php]$username = "Robert'); DROP TABLE People;";[/src]
wäre ein Angriff auf die Datenbank, gegen den du dich mit _real_escape_string absichern kannst. Das ist aber nicht der einzige Weg, den man gehen kann. Prepared Statements sollten hier der bessere weg sein.

[src=php]$username = "<script>alert('suck my big fat ...')</script>";[/src]
wäre allerdings ein Angriff, der zwar der Datenbank nicht weh tut, aber im Ausgabekontext (wahrscheinlich einer HTML-Seite) Schaden anrichten kann.
Dagegen musst du dich ebenfalls schützen.
Das kannst du jetzt gleich über mehrere Ansätze:
1. Du überprüfst vorm Speichern, ob es sich um eine zulässige Eingabe handelt.
2. Du stellst bei der Ausgabe sicher, dass die Ausgabe als "Text" und nicht als interpretierbare Zeichen/ Anweisungen im Ausgabekontext interpretiert werden.


Insgesamt gibt es diverse Wege, die zielführend sein können, ggf. auch sind, aber mindestens genau so viele, die es nicht sind.



Ein Angriffsszenario welches ich kenne besteht darin, dass man beispielsweise eigene Werte in ein Auswahlfeld einschleust. Wie unterbindet man sowas beispielsweise? Welche Befehle sind für ein sicheres Formular noch von Relevanz und welche kann man eigentlich vergessen, bzw. spielen nur in bestimmten Situationen (Mail / File-Upload) eine Rolle?
Der sauberste Ansatz ist, prinzipiell alles, was vom Nutzer kommt als böse zu betrachten.
Du kannst Formulare zwar in bestimmtem Maße "schützen", aber der Aufwand dazu steht in keinem Verhältnis zu der Sicherheit [keinesfalls eine vollständige!], die du durch die Maßnahmen gewinnst. Daher ist es optimaler einfach prinzipiell jedes Datum, welches der Nutzer überträgt als Bedrohung zu betrachten.

Pattern matching kann in einigen Fällen ausreichend sein, wird aber unsicherer, je komplexer die akzeptierte Eingabe werden kann. Für Email gibt es im Netz gefühlt 132048629 vorgefertigte Pattern, die (angeblich) Emailadressen auf ein valides Format prüfen können sollen. Bisher habe ich keine gefunden, die wirklich das komplette Spektrum an validen Emailadressen abdeckt und nicht gleichzeitig invalide Formate zulässt.

Wenn du dem Nutzer eine Auswahl vorgeben willst, aus der er wählen kann, dann solltest du das Ergebnis ebenfalls noch mal prüfen:

[src=html5]<select name="gebaeck">
<option>Kuchen</option>
<option>Torte</option>
<option>Muffins</option>
</select>[/src]

Du kannst dich nicht darauf verlassen, dass wirklich auch nur eine der drei Optionen zurück kommt oder dass überhaupt gebaeck gesetzt sein wird.
Also musst du prüfen, ob das Feld gesetzt ist und ob es Kuchen oder Torte oder Muffins ist.


Dein

$variable = string($variable);

ist in PHP absolut unsinnig, denn:

[src=php]$variable = "Robert'); DROP TABLE People;";;
$variable = string($variable);
echo $variable;[/src]

Erzeugt:
[src=html5]"Robert'); DROP TABLE People;";[/src]

A. Alle Daten, die über ein Formular kommen, sind erstmal String
B. PHP verwendet dynamische Typisierung
C. Ein Cast auf String ändert an dieser Stelle genau überhaupt nichts.
Ebenfalls hilft es dir nichts in dem zweiten oben geschilderten Angriffsszenario.



PS: Ich habe versucht alles, was mir spontan als nennenswert erscheint, kurz anzureißen. Keinenfalls ist die Information vollständig.
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
Ein anderer oder zusätzlicher Ansatz ist es auch Stored Procedures zu verwenden- diese sind seit einiger Zeit auch in mysql möglich.
Du schreibst dir eine Procedure z.B. "insertMyUser(Username,vorname,nachname,BH-Größe).
Du übergibst dann die einzelnen Parameter und setzt diese in der Procedur auch an die von dir vorgesehenen Stellen in einer Tabelle ein.
Ein ungeplanter "merkwürdiger" Parameter von einem Angreifer wird dann in vielen Fällen zu einem Syntax-error beim ausführen der Procedure führen.
 

accC

gesperrt

Registriert
14 Juli 2013
Beiträge
5.250
Kannst du mal ein Beispiel dafür machen? Hört sich interessant an..
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
ein Beispiel für eine Procedure oder für einen Angriff?
Procedure is kein Problem... Angriff schon eher da ich da irgendwie immer zu einfallslos bin für ein realistisches Beispiel :D ... bin viel zu Brav ;P
 

accC

gesperrt

Registriert
14 Juli 2013
Beiträge
5.250
Für Procedure.. das Prinzip hinter SQL-Injections kenne und verstehe ich, auch wenn ich in der Regel auch zu dämlich bin, selbst etwas derartiges zu konstruieren :D
 

Kugelfisch

Nerd

Registriert
12 Juli 2013
Beiträge
2.342
Ort
Im Ozean
$variable = string($variable);
ist in PHP absolut unsinnig, denn:
[...]
A. Alle Daten, die über ein Formular kommen, sind erstmal String
Nein, das ist nicht korrekt. PHP akzeptiert in POST-Daten und Query-Strings sowohl Strings als auch Arrays(!), welche über eine Syntax der Form [kw]foo[23]=bar[/kw] oder auch [kw]foo[]=bar[/kw] übergeben werden. Das kann zu Problemen führen, wenn im Folgenden Funktionen verwendet werden, welche keine Arrays als Parameter erwarten und/oder typenschwache Vergleiche durchgeführt werden. Triviales Beispiel:
[src=php]if(strcmp($_POST['password'], 't0psecret') == 0)
echo 'logged in';[/src]
Wird in diesem Fall anstelle eines Strings ein Array mit Namen `password` in den POST-Daten übergeben (z.B. [kw]password[]=23[/kw]), wird [kw]strcmp[/kw] eine Warnung ausgeben und [kw]NULL[/kw] zurückliefern, welche im typenschwachen Vergleich 0 entspricht. Ein Angreifer könnte den Vergleich demnach umgehen, auch ohne das Passwort `t0psecret` zu kennen. Ähnliche Probleme können in Cyperfriends Anwendungsfall z.B. auftreten, wenn Prepared Statements verwendet werden und da Datenbank-Backend es optional erlaubt, mehrere Parameter in Form eines Arrays auf Einmal zu übergeben - dann könnte der Angreifer u.U. Datenbankfelder manipulieren, welchen ein konstanter Wert zugewiesen werden sollte.

Daher ist ein expliziter String-Typecast keineswegs sinnlos. Er ist genau dann erforderlich, wenn nicht anderweitig sichergestellt wird, dass ein unerwartet übergebenes Array eventuelle weitere Überprüfungen besteht ([kw]preg_match[/kw] wird z.B. immer [kw]FALSE[/kw] und eine Fehlermeldung liefern, wenn der zweite übergebene Parameter ein Array ist).

Ein ungeplanter "merkwürdiger" Parameter von einem Angreifer wird dann in vielen Fällen zu einem Syntax-error beim ausführen der Procedure führen.
Das gilt allerdings auch dann, wenn die Eingaben ohne jegliche Maskierung direkt in ein SQL-Query konkateniert werden. Dass bei ungezielten `seltsamen` Eingaben wie z.B. [kw]'">[/kw] ein Syntax-Fehler entsteht, bedeutet nicht, dass an dieser Stelle mit einer gezielten `seltsamen` Eingabe wie z.B. [kw]'; DROP TABLE foo; -- 42[/kw] kein Exploit möglich ist. Insofern bietet dieses Vorgehen maximal Security-by-Obscurity.


Grundsätzlich kann ich mit epiphora und keksautomat anschliessen. Zunächst solltest du zumindest rudimentär das Format aller Eingaben verifizieren, syntaktisch und ggf. auch semantisch (passen eventuelle redundante Eingaben wie z.B. PLZ und Ort zusammen?). Stelle sicher, dass alle Eingaben, sofern nicht explizit anders erwartet, Strings sind. Verwende MySQLi oder PDO in Verbindung mit Prepared Statements, dann entfällt das datenbankspezifische Maskieren der Eingaben, da Query und Daten getrennt bleiben. Stelle ggf. sicher, dass Einträge nicht mehrfach hinzugefügt werden können, im Idealfall über Datenbank-Constraints (UNIQUE-Felder u.ä.) in Verbindung mit einer sinnvollen Fehlerbehandlung.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #10
Also was ihr alles schreibt ist gut und schön, kann man aber auf zahlreichen anderen Seiten nachlesen. Ich hatte mal auf ein vernünftiges Codebeispiel gehofft, wo erklärt wird wie man sich codetechnisch gegen die Angriffe zur Wehr setzt und nicht nur drüber gesprochen wird, was man machen kann. Das WIE ist worum es geht und womit ich nicht klar komme.
 

accC

gesperrt

Registriert
14 Juli 2013
Beiträge
5.250
Nein, das ist nicht korrekt. (...) Triviales Beispiel:
[src=php]if(strcmp($_POST['password'], 't0psecret') == 0)
echo 'logged in';[/src]
Wird in diesem Fall anstelle eines Strings ein Array mit Namen `password` in den POST-Daten übergeben (z.B. [kw]password[]=23[/kw]), wird [kw]strcmp[/kw] eine Warnung ausgeben und [kw]NULL[/kw] zurückliefern, welche im typenschwachen Vergleich 0 entspricht.

Okay, da haben wir wohl unterschiedliche Sichtweisen.
Für mich ist strcmp so definiert, dass int oder null zurück gegeben wird.
Dann ist es Aufgabe der Vergleichsfunktion zwischen (int)0 und null zu unterscheiden.
Das macht man allerdings mit === und nicht mit ==.

Für mich liegt der Fehler also im if(... == 0) und nicht in den Parametern von strcmp.
Aber gut, das ist eben abhängig von der Sichtweise.
 

evillive

EXIL

Registriert
24 Juli 2013
Beiträge
930
@Cyperfriend:

entscheident ist wie accC schon erwähnt hat der Kontext.

Wenn du in die Datenbank schreibst, dann musst du dich für SQL-Injection schützen. Hier wurde ja z. B. Prepared Statements genannt.


Wenn du Daten aus der Datenbank holst, und diese im Browser ausgeben willst, dann musst du schauen, dass sie kein Javascript und HTML (außer es ist so gewohlt) enthalten.
 

Kugelfisch

Nerd

Registriert
12 Juli 2013
Beiträge
2.342
Ort
Im Ozean
Ich hatte mal auf ein vernünftiges Codebeispiel gehofft, wo erklärt wird wie man sich codetechnisch gegen die Angriffe zur Wehr setzt und nicht nur drüber gesprochen wird, was man machen kann. Das WIE ist worum es geht und womit ich nicht klar komme.
Diverse Codebeispiele für die Verwendung von Prepared Statements findest du in der PHP-Dokumentation z.B. unter http://www.php.net/manual/de/mysqli-stmt.bind-param.php für MySQLi und unter http://www.php.net/manual/de/pdostatement.bindvalue.php für PDO. Die syntaktische und ggf. semantische Überprüfung lässt sich nicht pauschalisieren, diese hängt davon ab, welche Eingaben bzw. Datentypen du konkret erwartest. Im Allgemeinen Fall kann man aufgrund der in meinem letzten Beitrag genannten Problematik nur raten, die Werte aus $_GET bzw. $_POST explizit zu einem String zu casten.

Für mich liegt der Fehler also im if(... == 0) und nicht in den Parametern von strcmp.
Aber gut, das ist eben abhängig von der Sichtweise.
Nein, ich stimme dir in Bezug auf das Beispiel zu, dass (auch) der typenschwache Vergleich zu beanstanden ist - das Beispiel sollte bloss aufzeigen, dass die Inhalte von $_GET und $_POST eben nicht zwingend Strings sind, und dass sie deshalb ohne expliziten Typecast nur an Funktionen übergeben werden dürfen, deren Verhalten bei der Übergabe eines Arrays als Parameter definiert und bekanntermassen harmlos ist (was bei strcmp() nicht der Fall ist - dass im Fehlerfall NULL zurückgeliefert ist, ist in http://www.php.net/manual/en/function.strcmp.php nicht dokumentiert). Im Allgemeinen ist ein expliziter Typecast daher durchaus sinnvoll.
 

Cyperfriend

Der ohne Avatar

Registriert
14 Juli 2013
Beiträge
1.123
  • Thread Starter Thread Starter
  • #14
Also in meinem Fall geht es nur um Text. Keine Bilder, keine Dateien, nur Text ala "Max Mustermann" oder Daten aus einem Auswahlmenü.
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.758
Ort
in der Zukunft
@Acc ein Beispiel wie ich das meinte poste ich morgen... jetzt ist es mir zu Spät :D
@Cyperfriend - wenn es wirklich nur um z.B. Namen und Wörter geht kannst du den gesamten Inhalt der in die DB geht per Regex auf A-Za-Z0-9 Leerzeichen und Bindestrich beschränken, bzw. alle anderen Zeichen außer diese ersetzen durch "nichts". Zusätzlich (wenn nicht als Input benötigt) SQL-Befehle wie DELETE,SELECT,INSERT ebenfalls filtern. Dann dürfte "glaube" ich nichts mehr passieren können.
Jede SQL-Injection müsste doch ein ; erfordern?
 

Kugelfisch

Nerd

Registriert
12 Juli 2013
Beiträge
2.342
Ort
Im Ozean
@Cyperfriend - wenn es wirklich nur um z.B. Namen und Wörter geht kannst du den gesamten Inhalt der in die DB geht per Regex auf A-Za-Z0-9 Leerzeichen und Bindestrich beschränken, bzw. alle anderen Zeichen außer diese ersetzen durch "nichts". Zusätzlich (wenn nicht als Input benötigt) SQL-Befehle wie DELETE,SELECT,INSERT ebenfalls filtern.
Das Filtern von SQL-Schlüsselwörtern ist in der Regel wenig sinnvoll und oftmals leicht zu umgehen: Wenn z.B. `SELECT` durch eine leere Zeichenkette ersetzt wird, würden sich Konstrukte wie z.B. `SELSELECTECT` anbieten, welche nach der Filterung zu `SELECT` werden. Die Einschränkung des Zeichensatzes kann sinnvoll sein, erschwert allerdings auch die Eingabe internationaler Sonderzeichen (z.B. deutsche Umlaute, französische Accents, kyrillische oder griechische Zeichen) und sollte daher mit Bedacht angewendet werden.

Wenn Prepared Statements verwendet werden, sind solche Einschränkungen allerdings gar nicht notwendig, da die Injection-Problematik nicht auftritt, da Daten und Query getrennt bleiben. Das Query enthält bloss Platzhalter für die Daten, welche separat an den Datenbanktreiber (und in vielen Fällen auch an das DBMS) übergeben werden. Dadurch können Prepared Statements sogar effizienter sein, wenn dasselbe Query wiederholt mit verschiedenen Daten ausgeführt wird, da es dann nur einmal geparst werden muss.

Also in meinem Fall geht es nur um Text.
Wenn du kein bestimmtes Format erwartest, bliebe bloss noch die Daten in einen String zu casten und dann mittels Prepared Statements in die Datenbank zu schreiben. Wenn bestimmte Spalten einmalige Werte annehmen sollen, setze für die entsprechenden Spalten ein UNIQUE-Constraint in der Datenbank. Überprüfe, ob das Query korrekt ausgeführt wurde, und lasse ggf. eine Fehlermeldung ausgeben.
 

keksautomat

Neu angemeldet

Registriert
15 Juli 2013
Beiträge
471
Da du Daten aus einem Auswahlmenü erwartest, würde ich auch immer noch gegenprüfen, ob X (das was durch kam) auch in Y (die Items aus dem Auswahlmenu) enthalten ist. Wenn nein, dann eine Fehlermeldung schmeissen und nichts tun.
 
Oben