Maison > Article > développement back-end > Un article analysant comment les requêtes prétraitées de PHP empêchent l'injection SQL
Cet article vous apporte des connaissances pertinentes sur PHP. Il parle principalement de ce qu'est une instruction de prétraitement ? Comment la requête prétraitée de PHP empêche-t-elle l'injection SQL ? Les amis intéressés peuvent jeter un œil ci-dessous. J'espère que cela sera utile à tout le monde.
Comment la requête prétraitée de PHP empêche-t-elle l'injection SQL ?
Actuellement, le moyen le plus efficace d'empêcher l'injection SQL consiste à utiliser des instructions préparées et des requêtes paramétrées.
Prenons l'exemple de l'extension PHP PDO la plus couramment utilisée.
Introduction aux déclarations préparées dans la documentation officielle
Que sont les déclarations préparées ?
Considérez-le comme un modèle compilé du SQL que vous souhaitez exécuter, qui peut être personnalisé à l'aide de paramètres variables.
Deux avantages majeurs des instructions préparées :
1 ; La requête ne doit être analysée (ou prétraitée) qu'une seule fois, mais peut être exécutée plusieurs fois avec des paramètres identiques ou différents. Lorsqu'une requête est prête, la base de données analyse, compile et optimise le plan d'exécution de la requête. Ce processus prend plus de temps pour les requêtes complexes et peut ralentir considérablement votre application si la même requête doit être répétée plusieurs fois avec des paramètres différents. En utilisant des instructions préparées, vous pouvez éviter les cycles répétés d’analyse/compilation/optimisation. En termes simples, les instructions préparées utilisent moins de ressources et s'exécutent donc plus rapidement.
2. Les paramètres fournis à la déclaration préparée n'ont pas besoin d'être mis entre guillemets, le pilote les gérera automatiquement. Si votre application utilise uniquement des instructions préparées, vous pouvez vous assurer qu'aucune injection SQL ne se produit. (Cependant, si d'autres parties de la requête sont construites à partir d'entrées non échappées, il existe toujours un risque d'injection SQL).
La caractéristique de PDO est que lorsque le pilote ne prend pas en charge le prétraitement, PDO simule le traitement. À ce stade, le processus de requête paramétré par prétraitement est terminé dans le simulateur PDO. Le simulateur PDO échappe localement les paramètres d'entrée en fonction du jeu de caractères spécifié dans le DSN, puis les fusionne en une instruction SQL complète et l'envoie au serveur MySQL.
Donc, savoir si le simulateur PDO peut échapper correctement aux paramètres d'entrée est la clé pour intercepter l'injection SQL.
Pour les versions PHP inférieures à 5.3.6, DSN (Data Source Name) ignore le paramètre charset par défaut. À l'heure actuelle, si vous utilisez l'échappement local de PDO, cela peut toujours conduire à une injection SQL.
Par conséquent, la couche inférieure du framework Laravel définira directement PDO::ATTR_EMULATE_PREPARES=false pour garantir que les instructions SQL et les valeurs des paramètres ne seront pas analysées par PHP avant d'être envoyées au serveur MySQL.
L'implémentation de PHP
// 查询 $calories = 150; $colour = 'red'; $sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindValue(':calories', $calories, PDO::PARAM_INT); $sth->bindValue(':colour', $colour, PDO::PARAM_STR); $sth->execute();
// 插入,修改,删除 $preparedStmt = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStmt->execute(array(':column' => $unsafeValue));
L'implémentation sous-jacente de Laravel
// 查询的实现 public function select($query, $bindings = [], $useReadPdo = true) { return $this->run($query, $bindings, function ($query, $bindings) use ($useReadPdo) { if ($this->pretending()) { return []; } $statement = $this->prepared( $this->getPdoForSelect($useReadPdo)->prepare($query) ); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); return $statement->fetchAll(); }); } // 修改删除的实现 public function affectingStatement($query, $bindings = []) { return $this->run($query, $bindings, function ($query, $bindings) { if ($this->pretending()) { return 0; } $statement = $this->getPdo()->prepare($query); $this->bindValues($statement, $this->prepareBindings($bindings)); $statement->execute(); $this->recordsHaveBeenModified( ($count = $statement->rowCount()) > 0 ); return $count; }); }
Apprentissage recommandé : "Tutoriel vidéo PHP"
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!