Wie sicher ist $pdo->prepare($query)
lima-city → Forum → Programmiersprachen → PHP, MySQL & .htaccess
adresse
all
anfrage
array
boot
code
email
fehl
filter
filtern
funktion
fusion
gefilterte eingabe
problem
richtiger verwendung
spielerei
statement
string
url
verwenden
-
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
all-in1 schrieb:
Da kann nichts mehr schief gehen - vorausgesetzt, du verwendest es auch richtig. Die
Wie sicher ist$pdo->prepare($query)
muss konstant sein oder aus sicherer Quelle kommen. Also auf keinen Fall ungefiltert Benutzereingaben einfügen. Diese werden über$query
mit eingebunden und alles ist sicher. Die Funktionsweise ist etwas anders, als beibind_param
, doch das passiert alles zwischen dem PHP-Parser und DB-Server. Das PHP-Skript hat mit der Maskierung nicht mehr direkt zu tun.mysql_real_escape_string()
all-in1 schrieb:
Und wie sicher sind die Filter Funktionen von PHP, [...]
String:
Meinst du das?filter_var($userInput, FILTER_SANITIZE_STRING);
Dann erklär mir bitte mal jemand, was diese Funktion tut, außer alles in einen String zu verwandeln. Schlägt die auch irgendwann mal fehl und gibt false zurück?
Oder anders gefragt: Wenn du einen String prüfst, welche Bedingung sollte dieser deiner Meinung nach erfüllen?
Url:
filter_var($userInput, FILTER_VALIDATE_URL);
Diese prüft nur, ob es sich um eine Url handeln könnte. Vergiss aber nicht zu maskieren, wenn du z.B. einen Link zusammenbaust.
E-Mail:
filter_var($userInput, FILTER_VALIDATE_EMAIL);
Diese Funktion arbeitet sehr streng. Du kannst die gefilterte Eingabe verwenden, um an die Adresse eine E-Mail zu senden. Ein Angreifer kann dann über deinen Webserver keine Spam-Mails (mit eigenem Text) versenden. Ohne Filter wäre das dagegen denkbar. -
Die Frage ist ungefähr so so beantworten wie "Wie sicher ist dieses Boot auf hoher See". Es kommt drauf an wie du es fährst (naja, und auf das Boot, aber PDO ist ein sehr gutes)!
Prinzipiell, wenn du prepared Statements korrekt verwendest, sind mir keine Angriffsmöglichkeiten mehr bekannt, aber fangen wir vorne an.
Eine SQL Injektion funktioniert durch ein ungewolltes manipulieren des SQL Statements. Das passiert besonders einfach durch das unachtsame verwenden von GPC (Nutzereingaben):
mysql_query('SELECT * FROM `users` WHERE password=' . $_GET['data']);
Ein prepared Statement geht dabei aber total anders mit dem SQL Statement um. Vereinfacht gesagt evaluiert das prepare das Statement bereits, und es wird bereits übersetzt. Das heißt, das Statement ist nicht mehr änderbar. Du fütterst es nurnoch mit Daten:
$stmt = $pdoDb->prepare('SELECT * FROM `users` WHERE password=?'); $stmt->execute(array($_GET['data']));
Dadurch, dass das Prepare die Query unveränderbar macht, kann das Execute beinhalten was du willst, es wird immer sicher vor SQL Injections sein.
Wenn du allerdings:
$stmt = $pdoDb->prepare('SELECT * FROM `users` WHERE password=' . $_GET['data']); $stmt->execute();
Schreibst, hast du nichts gewonnen, weil dann die Nutzereingaben mit ausgewertet werden.
Bei richtiger Verwendung ist mir keine Möglichkeit bekannt, wie eine SQL Injection noch möglich ist. Bei falscher Verwendung gibt es die selben Probleme.
mysqli_real_escape_string escaped den String, sodass "Böse" Zeichen nicht mehr ausgewertet würden. Ob man das umgehen kann, weiß ich nicht.
Und welche Filterfunktionen meinst du genau?
Meistens liest man inden Kommentaren zu der Doku auf php.net schon hilfreiche Dinge, wie gut etwas ist. Bei den Email Filtern war damals, wenn ich mich recht erinnere, das Problem, dass sowas wie @test valide war, ohne eine Topleveldomain. KA ob das noch besteht
Liebe Grüße
Beitrag zuletzt geändert: 3.7.2015 20:44:51 von ggamee -
Ich bin gerade dabei mir einen dbhandler auf zubauen. War früher ja mal aktiv bei PHP-Fusion und habe mich da an die Funktionen etwas gewöhnt.
Also wäre so etwas sicher:
function dbquery($query, $execute='') { global $pdo, $mysql_queries_count, $mysql_queries_time; $mysql_queries_count++; $query_time = get_microtime(); $result = $pdo->prepare($query); $query_time = substr((get_microtime()-$query_time), 0, 7); $mysql_queries_time[$mysql_queries_count] = array($query_time, $query); if (!$result) { print_r($result->errorInfo()); return FALSE; } else { $result->execute($execute); return $result; } } function check_user($name, $pass){ $sql="SELECT userid FROM ".DB_USER." WHERE user_name=:name AND user_pass=:pass LIMIT 1"; $result= dbquery($sql, array(':name' => $name , ':pass' => $pass)); if ($result){ $user=dbarray($result); return $user['userid']; }else return false; }
Wobei das Passwort schon bei Aufruf der Funktion entsprechend gehascht wird.
Bei den Filtern benötige ich der Regel nur Email, URL, und natürlich integer, wobei man letzteres ja auch sehr gut mit is_numeric validieren kann.
Mir geht es dabei in erster Linie auch nicht darum, ob es dann wirklich eine Email Adresse ist, sondern nur darum, dass man eben Spammails vermeidet.
Bei der Url ja auch nur darum, dass kein Crosssitescripting möglich ist. Obwohl ich das auch noch etwas anders zusätzlich filtere. Nur wäre es durch aus schön, wenn ich eben den zusätzlichen Filter nicht benötigen würde, da es doch ein paar Zeilen Code mehr sind.
-
XSS oder Header-Injections verhinderst du damit allerdings nicht. Lediglich SQL-Injections.
Den Rest musst du selbst bei Ausgabe filtern. Das ist wie mit HTML-Spielereien und htmlentities.
OT: Wofür benutzt du denn $mysql_queries_count und nicht einfach nur $mysql_queries_time[]. -
muellerlukas schrieb:
OT: Wofür benutzt du denn $mysql_queries_count und nicht einfach nur $mysql_queries_time[].
$mysql_queries_count zählt alle DB Anfragen. Ich selbst benötige es zur Zeit gar nicht.
Eventuell nachher bei einem meiner Großprojekte wieder, damit man sehen kann, wo noch etwas verbessert werden kann.
Den Code habe ich noch mal etwas geändert nach einem Testlauf.
function dbquery($query, $execute=array()) { global $pdo, $mysql_queries_count, $mysql_queries_time; $mysql_queries_count++; $query_time = get_microtime(); $result = $pdo->prepare($query); $query_time = substr((get_microtime()-$query_time), 0, 7); $mysql_queries_time[$mysql_queries_count] = array($query_time, $query); if (!$result) { print_r($result->errorInfo()); return FALSE; } else { $result->execute($execute); return $result; } }
So funktioniert das ganze besser und man muss den 2 Parameter nicht unbedingt angeben. Zum Beispiel bei Anfragen, wo definitiv keine SQL Injections möglich sind. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage