Programmierung
Datenbank-Sicherheit mit Prepared Statements
Datenbank-Sicherheit, insbesondere im Zusammenhang mit sogennanten SQL-Injections (Fremdangriffe durch Hacker) ist immer wieder ein Thema für Web-Programmierer. Als ein probates Mittel dagegen haben sich Prepared Statements erwiesen. Nun bietet auch PHP in neueren Versionen diese Funktionalität.
Relativ problemlos läßt sich mit PHP ab 5.1 mit Prepared Statements arbeiten. Versionen davor sind entweder garnicht in der Lage oder aber mit erheblichem Mehraufwand und Installation. Unversierte Nutzer kann das auch mal schnell überfordern.
Dreh- und Angelpunkt ist das sogenannte PDO-Modul, welches gebraucht wird.
mit
<?php
phpinfo();
?>
läßt sich zügig ermitteln, ob es vorhanden ist. In der Ausgabe sollte z.B. sowas zu finden sein:
PDO
PDO support enabled
PDO drivers mssql, mysql, sqlite2
und ungefähr sowas, wenn man mysql nutzt:
pdo_mysql
PDO Driver for MySQL, client library version 5.0.21
Nun zum Quelltext, wie man PDO sinnvoll nutzen kann:
<?php
try {
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$stmt = $dbh->prepare("SELECT * FROM tabelle WHERE vorname = :vorname AND nachname = :nachname");
$stmt->bindParam(':vorname', "Hans");
$stmt->bindParam(':nachname', "Meier");
if ($stmt->execute()) {
while ($row = $stmt->fetch()) {
print_r($row['vorname']);
}
}
$dbh = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
try-catch: Für Java-Enwickler nichts Neues, für manchen PHP-Entwickler
schon. Man nennt es auch Exception-Handling, denn im Falle eines
Fehlers kann man das weitere Verhalten explizit sehr komfortabel
bestimmen. Der catch-Block fängt den Fehler quasi ab, die darin
enthaltenen Anweisungen werden dann ausgeführt.
$dbh = new PDO('mysql:... Die Verbindung zur Datenbank wird aufgebaut. (hier mysql)
$stmt = $dbh->prepare... Die Abfrage wird vorbereitet, "präpariert".
$stmt->bindParam... Die Parameter werden ans Statement gegeben.
$stmt->execute(); Die Abfrage wird ausgeführt.
while ($row = $stmt->fetch()) Die Ergebnismenge wird zeilenweise abgearbeitet.
$dbh = null; Die Verbindung wird geschlossen.
Was auch geht:
$stmt = $dbh->prepare("SELECT * FROM tabelle WHERE vorname = ? AND nachname = ?");
$stmt->bindParam(1, "Hans");
$stmt->bindParam(2, "Meier");
Ich sehe keinen expliziten Vorteil für das eine oder andere, würde mich über eine Belehrung freuen.
Kommentare
Ich nehme Tor 1 und bitte jeden Entwickler, Variante 2 der Parameterbindun g nach Möglichkeit nicht zu benutzen.
Grund: durch explizite Benennung ist der Quellcode deutlich lesbarer und somit auch langfristig leichter zu warten.
Bei Anweisungen wie
$stmt->bindParam(14, "foo");
das vierzehnte Fragezeichen aus der Abfrage herauszusuchen, ist halt doch eher ermüdend.
Und mehr noch: man stelle sich Abfrage mit mehreren Parametern ( > 10 etwa) vor. Sollte es nun nötig sein, an dritter Stelle einen weiteren Parameter einzufügen, so muss die Nummerierung aller folgenden Parameter aktualisiert werden - ein Aufwand, der sich bei der benannten Variante nicht ergibt, hier muss nur eine neue Bezeichnung erdacht werden.
So long,
Michael
Alle Kommentare dieses Beitrages als RSS-Feed.