Emulierte preperade Statements mittels PDO::ATTR_EMULATE_PREPARES
PDO hat Standardmäßig das Emulieren von Prepared Statements aktiviert. In diesem Artikel erfahrt ihr, was es damit auf sich hat und welche Vor- und Nachteile sich ergeben.
Um es vorweg zu sagen: Für 95% aller Entwickler und Anwendungen wird es wohl keinen Unterschied machen, ob echte Prepared Statements genutzt werden oder ob diese von PDO emuliert werden.
Was sind emulierte Prepared Statements?
Prepared Statements ist die sicherste Methode um sich vor SQL-Injections zu schützen wird von vielen Entwicklern genutzt. Allerdings unterstützen nicht alle Datenbanksysteme Prepared Statements. MySQL unterstützt es seit Version 5, ein paar alte Webhoster und Websites nutzen aber immer noch beispielsweise MySQL4. Andere Datenbanksysteme die ihr mittels PDO ansprechen könnt unterstützen überhaupt keine Prepared Statements.
Damit ihr bei solchen Datenbanken dennoch mit Prepared Statements arbeiten könnt, emuliert PDO diese. Bei echten Prepared Statements wird das Query und die Daten separat an den Datenbankserver gesendet. Beispielsweise habt ihr ein Query wie das folgende:
1 |
SELECT * FROM tabelle WHERE id = ? |
Wenn ihr dieses ausführt, dann würde dieses Query und der Wert für den Parameter separat an den Datenbankserver gesendet. Da der Datenbankserver explizit weiß, was zum SQL-Query gehört und was Daten sind, ist eine SQL-Injection nicht möglich.
Bei einem emulierten Prepared Statement setzt PDO im SQL-Query alle Werte ein und sendet ihn dann an den Datenbankserver. Führt man das obige Statement mit dem Wert 5 aus, so sendet PDO an die Datenbank das folgende Query:
1 |
SELECT * FROM tabelle WHERE id = 5 |
Die Parameter werden von PDO natürlich richtig maskiert um einen Schutz vor SQL-Injections zu bieten. Durch diesen Trick ermöglicht es PDO, dass man als Entwickler die wichtigsten Vorteile von Prepared Statements nutzen kann, selbst wenn der Datenbankserver dies gar nicht unterstützt.
Emulierte Prepared Statements aktivieren / deaktivieren
Standardmäßig ist das Emulieren von Prepared Statements in PHP aktiviert. Möchtet ihr dieses deaktivieren und stattdessen echte Prepared Statements nutzen die von der Datenbank bereitsgestellt werden, so geht dies mittels dem Attribut PDO:ATTR_EMULATE_PREPARES.
1 2 3 4 |
<?php $pdo = new PDO('mysql:host=localhost;dbname=databasename', 'username', 'password'); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); ?> |
Sollte der Datenbankserver keine prepared Statements unterstützen, so fällt PDO auf das Emulieren zurück. Sprich, auch wenn ihr es auf false setzt, so wird eure Anwendung funktionieren.
Vor- und Nachteile
Bei dem Thema wird sich am meisten über das Thema Sicherheit und das Thema Performance gestritten.
Sicherheit
Ein häufiges Pro-Argument für echte Prepared Statments ist das Thema Sicherheit. Sollte in der PDO-Klasse ein Fehler vorhanden sein, so wären SQL-Injections möglich. Das richtige Maskieren von Eingaben ist aufgrund der großen Anzahl unterschiedlicher Zeichensätze nicht trivial, also wäre es schon möglich dass ein entsprechender Fehler in PDO vorhanden sein könnte, der SQL-Injections ermöglicht. Die Wahrscheinlichkeit dafür ist meiner Einschätzung nach aber nicht sonderlich hoch.
Fazit: Echte, native Prepared Statements dürften minimal mehr Sicherheit bieten, der Unterschied ist aber eher zu vernachlässigen.
Performance
Der zweite große Diskussionspunkt ist die Performance. Werden die selben Queries häufig hintereinander ausgeführt, so sind native Prepared Statements im Vorteil. Der SQL-Query muss hierbei nur einmal geparst werden und wird dann von MySQL immer wieder mit neuen Parametern gefüttert. Bei der Variante mittels emulierten Prepared Statements muss der Query jedes mal neu von der MySQL-Datenbank geparst werden. Dies ist tendenziell langsamer.
Solltet ihr hauptsächlich unterschiedliche Queries in einem PHP Scripts ausführen, so sind die emulierten Statements im leichten Vorteil. Denn hier muss nur einmal mit dem Datenbankserver kommuniziert werden, um diesen das finale SQL-Query zu übermitteln.
Fazit: Von der Performance dürfte es für 95% der Anwendungen kaum einen Unterschied machen. Ebenfalls ist das kritische Bottleneck bei Datenbanken heutzutage der langsame Zugriff auf die Festplatte. Der minimale Parsing-Overhead bei emulierten Statements bzw. der minimale zusätzliche Kommunikationsaufwand bei nativen prepared Statements fällt dort nicht ins Gewicht.
Emulierung aktivieren oder deaktivieren?
Im Grunde macht es keinen Unterschied, ob ihr es aktiviert oder deaktiviert. Der Funktionsumfang ist identisch, bzgl. der Sicherheit macht es auch keinen großen Unterschied und von der Performance macht es für die meisten Anwendungen auch keinen Unterschied. Falls ihr dieses Thema aber nicht ungeklärt lassen möchtet, dann sollte ihr es tendenziell lieber wie oben beschrieben deaktivieren.
Autor: Nils Reimers