Protéger les comportements de serveur PHP contre la vulnérabilité d'injection SQL

Dernière mise à jour le 27 avr. 2021

Problème

Certaines bases de données vous permettent d’envoyer plusieurs instructions SQL dans une seule requête de recherche. Par conséquent, il existe des risques de sécurité potentiels lorsque vous transmettez des paramètres dans une chaîne de requête à une requête de base de données générée dynamiquement. Les pirates pourraient tenter de modifier l'URL ou les variables de formulaire dans une requête dynamique en ajoutant des instructions SQL malveillantes aux paramètres existants. Cela est souvent connu sous le nom d’attaque par injection de code SQL. Une partie du code de comportement de serveur créé par Dreamweaver doit être modifiée afin de réduire le risque d’attaques par injection de code SQL. Pour obtenir des informations supplémentaires sur les attaques par injection de code SQL, voir cet article Wikipedia. (N° de référence : 201713)

Remarque : Le problème décrit dans cette note technique a été corrigé dans la mise à jour Dreamweaver 8.0.2.

Cette note technique couvre les comportements de serveur PHP de Dreamweaver. Il existe des notes techniques distinctes pour les comportements de serveur ColdFusion, ASP VBScript, ASP JavaScript et JSP.Les comportements de serveur ASP.NET ne sont pas affectés.

Solution

Lorsque vous laissez une chaîne de requête transmettre un paramètre, assurez-vous que seules les informations attendues sont transmises. Adobe a créé une mise à jour Dreamweaver 8.0.2 qui réduit le risque d'attaques par injection SQL. Ces corrections seront intégrées dans toutes les futures versions de Dreamweaver. Après avoir mis à jour Dreamweaver 8, vous devrez appliquer à nouveau les comportements de serveur aux pages qui les utilisent, et redéployer ces pages sur votre serveur.

Le reste de cette note technique explique comment modifier manuellement le code Dreamweaver MX 2004 pour empêcher les attaques par injection SQL avec le modèle de serveur PHP.Les comportements de serveur vulnérables à ces attaques sont répertoriés ci-dessous, avec les corrections correspondantes :

Jeu d’enregistrements avec un filtre

Les jeux d’enregistrements non filtrés n’ont pas besoin d’être modifiés, au contraire des jeux d’enregistrements filtrés. Dans l'exemple ci-dessous, un jeu d'enregistrements Dreamweaver MX 2004 nommé « rs_byDate » est filtré par une valeur de date transmise depuis un paramètre d'URL. Le code surligné ci-dessous est ce qui doit être modifié :

<?php $colname_rs_byDate = &quot;1&quot;; if (isset($_GET[&apos;relDate&apos;])) { $colname_rs_byDate = (get_magic_quotes_gpc()) ?$_GET['relDate'] : addslashes($_GET['relDate']); } mysql_select_db($database_dreamqa2, $dreamqa2); $query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate); $rs_byDate = mysql_query($query_rs_byDate, $dreamqa2) or die(mysql_error()); $row_rs_byDate = mysql_fetch_assoc($rs_byDate); $totalRows_rs_byDate = mysql_num_rows($rs_byDate); ?>

Pour protéger le jeu d'enregistrements contre les attaques par injection SQL, une fonction GetSQLValueString() personnalisée doit être créée près du haut de la page. Cette fonction vérifie le type de données du paramètre de requête. Une fois la fonction créée, mettez ensuite à jour le code du jeu d'enregistrements pour utiliser la fonction GetSQLValueString().

Allez à la deuxième ligne en mode code, juste après le fichier d'inclusion pour la connexion, et ajoutez la fonction GetSQLValueString() au début du code comme suit :

<?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } ?>

Supprimez le code des guillemets magiques afin que les barres obliques inversées ne soient pas ajoutées de manière incorrecte aux données GET et POST lorsque les guillemets magiques sont désactivés sur le serveur PHP.

Code original :

$colname_rs_byDate = (get_magic_quotes_gpc()) ? $_GET['relDate'] : addslashes($_GET['relDate']);

Code modifié :

$colname_rs_byDate = $_GET['relDate'];



Mettez à jour le code du recordset pour créer une chaîne SQL en utilisant la fonction GetSQLValueString() créée ci-dessus.Mettez à jour la valeur de la variable $query_rs_byDate :

Code original :

$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = '%s'", $colname_rs_byDate);

Code sécurisé modifié :

$query_rs_byDate = sprintf("SELECT * FROM albums WHERE relDate = %s", GetSQLValueString($colname_rs_byDate, "date"));

Comportements de serveur Insérer, Mettre à jour et Supprimer l'enregistrement et assistant Formulaire d'insertion d'enregistrement

Les comportements de serveur Insérer, Mettre à jour et Supprimer l'enregistrement et l'assistant Formulaire d'insertion d'enregistrement utilisent déjà la fonction GetSQLValueString(), ils doivent donc être affinés pour empêcher les injections SQL. Les seules modifications nécessaires se trouvent dans la fonction GetSQLValueString().

Voici le code original. La ligne à modifier est surlignée en jaune :

if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") {$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue; switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } }

Mettez à jour la définition de la variable $theValue :

Code d'origine :

$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue;

Code sécurisé modifié :

$theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue);

Comportement de serveur de connexion de l’utilisateur

Voici les étapes pour corriger le comportement du serveur Connexion utilisateur :

Créez une fonction GetSQLValueString() comme décrit dans Jeu d'enregistrements avec un filtre ci-dessus.

Modifiez le code qui construit la requête SQL de connexion.



Code d'origine :

$LoginRS__query=sprintf("SELECT username, password FROM login WHERE username='%s' AND password='%s'", get_magic_quotes_gpc() ? $loginUsername : addslashes($loginUsername), get_magic_quotes_gpc() ? $password : addslashes($password));

Code sécurisé modifié :

$LoginRS__query=sprintf(&quot;SELECT username, password FROM login WHERE username=%s AND password=%s&quot;, GetSQLValueString($loginUsername, &quot;text&quot;), GetSQLValueString($password, &quot;text&quot;));

Comportement de serveur de vérification de nouvel utilisateur

Le comportement de serveur de vérification de nouvel utilisateur nécessite au préalable l’ajout d’un comportement de serveur d’insertion d’enregistrement à la page. La fonction GetSQLValuesString() est incluse avec le comportement serveur Insérer un enregistrement. Il suffit de mettre à jour GetSQLValuesString() pour mieux gérer l'injection SQL et de mettre à jour le comportement serveur Check New User pour utiliser cette fonction lorsqu'un paramètre est transmis.

Modifiez la première ligne de la fonction pour mettre à jour la fonction GetSQLValuesString() comme décrit dans Mettre à jour la définition de la Variable $theValue.

Modifiez le code pour construire la requête SQL de connexion afin d'utiliser GetSQLValuesString() pour transmettre les paramètres. Vers le haut de la page, localisez le code dans la section commençant par // *** Redirect if username exists.



Code d'origine :

$LoginRS__query = "SELECT username FROM login WHERE username='" . $loginUsername . "'"



Code sécurisé modifié :

$LoginRS__query = sprintf("SELECT username FROM login WHERE username=%s", GetSQLValueString($loginUsername, "text"));

Ensemble de maquettes de détails

Pour l’objet d’application d’ensemble de maquettes de détails, les modifications concernent principalement le jeu d’enregistrements que Dreamweaver crée pour la page de détails. Si vous ne disposez pas d’un jeu d’enregistrements filtré dans la maquette, celle-ci ne requiert aucune modification. Si vous avez un jeu d'enregistrements filtré, consultez jeu d'enregistrements avec un filtre pour mettre à jour le code du jeu d'enregistrements.

Dreamweaver crée un jeu d'enregistrements filtré dans la page de détail, de sorte que le code de ce jeu d'enregistrements doit être mis à jour pour utiliser une fonction GetSQLValueString() afin de transmettre les paramètres et sprintf() pour construire la chaîne SQL.

Créez la fonction GetSQLValueString() comme décrit dans Jeu d'enregistrements avec un filtre ci-dessus.

Mettez à jour le code de déclaration de variable et construisez la requête SQL en utilisant la fonction GetSQLValuesString().



Code d'origine :

$recordID = $_GET[&apos;recordID&apos;]; $query_DetailRS1 = &quot;SELECT * FROM albums WHERE ID = $recordID&quot;;



Code sécurisé modifié :

$colname_DetailRS1 = "-1"; if (isset($_GET['recordID'])) { $colname_DetailRS1 = (get_magic_quotes_gpc()) ? $_GET['recordID'] : addslashes($_GET['recordID']); } $query_DetailRS1 = sprintf("SELECT * FROM albums WHERE ID = %s", GetSQLValueString($colname_DetailRS1, "int"));

Assistant formulaire de mise à jour d'enregistrement

Mettez à jour le code pour le jeu d'enregistrements qui est requis pour le formulaire de mise à jour d'enregistrement comme décrit dans l'étape 2 de Jeu d'enregistrements avec un filtre.

Informations supplémentaires

Veuillez vous reporter à l'article suivant pour plus d'informations sur l'injection SQL : Article Wikipedia sur l'injection SQL.

Bulletin de sécurité Adobe : APSB 06-07 Vulnérabilité d'injection SQL dans le comportement serveur Dreamweaver.