2010-07-22 6 views
0

Je crée une interface simple qui permettra à un utilisateur de modifier des éléments CSS et HTML stockés dans une base de données Microsoft SQL. Cette interface utilise PHP5 et ADOdb.Empêcher une base de données de rejeter une entrée utilisateur

Pour quelque raison, ce formulaire rejettera toute entrée qui contient un ou plusieurs guillemets simples. Cette chaîne, par exemple, n'est pas autorisée: "background-image: url ('paper.gif');"

Je soupçonne ADOdb de filtrer agressivement les guillemets simples pour empêcher les attaques par injection SQL. Existe-t-il un moyen d'échapper l'entrée de l'utilisateur dans PHP pour permettre au caractère guillemet simple d'être stocké?

J'ai considéré la conversion automatique de tous les guillemets simples en guillemets doubles, mais il semble que cela a le potentiel de casser le balisage de l'utilisateur.

Il est sans doute pas très utile, mais voici un exemple du test que je utilise:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=Cp1252"> 
<title>Edit website</title> 
</head> 
<body> 
<h1>CSS Test</h1> 

<?php 
    include_once ('database.php'); 
    $table = "[User Site]"; 

    if (!isset($_REQUEST['dbname'])) { 
     return false; 
    } else { 
     $dbname = $_REQUEST['dbname']; 
     $db = Database::singleton($dbname); 

     //Push any new CSS to the database 
     if (isset($_POST['css'])) { 
      $css = $_POST['css']; 
      $sql = "UPDATE " . $table . 
        " SET html='" . $html . "', css='" . $css . "' " . 
        " WHERE dbnameId='" . $dbname . "'"; 
      $db->Execute($sql); 
     } 

     //Fetch any CSS from the database 
     $sql = "SELECT * FROM " . $table . " WHERE dbnameId='" . $dbname . "'"; 
     $data = recordToArray($db->Execute($sql)); 
     echo "<p>"; 
     $css = $data[0]['css']; 
    } 

    $rows = 20; 
    $cols = 80; 
?> 
<!-- Show the user a form --> 
<form action="test.php" method="post"> 
    CSS:<br> <textarea rows="<?php echo $rows ?>" cols="<?php echo $cols ?>" name="css"><?php echo $css ?></textarea><p> 
    <input type="hidden" name="dbname" value="<?php echo $dbname ?>" /> 
    <input type="submit" value="Update CSS" /> 
</form> 
</p> 
</body></html> 

Répondre

4

Vous utilisez ADODB, mais vous n'utilisez pas la fonctionnalité principale de presque toutes les bibliothèques d'abstraction de base de données qui ont déjà existé: espaces réservés/instructions préparées.

Vos requêtes échouent car les éléments ne sont pas correctement échappés. L'utilisation d'espaces réservés ajoute l'échappement automatique. Lisez sur the Param method, qui insérera le bon type d'espace réservé pour la base de données que vous utilisez. (Il semble que vous utilisez MSSQL, et je ne sais pas si elle utilise ? comme un espace réservé ou non.)

Au lieu de

$sql = "SELECT * FROM " . $table . " WHERE dbnameId='" . $dbname . "'"; 
$sth = $db->Execute($sql); 

Vous voulez quelque chose comme:

$sql = "SELECT * FROM $table WHERE dbnameId = " . $db->Param('dbname'); 
$psh = $db->Prepare($sql); 
$sth = $db->Execute($psh, array($dbname)); 

(Ceci n'est pas testé et peut être subtilement faux, s'il vous plaît lire la page de manuel lié pour un peu plus d'informations.Ai-je mentionné que ADODB est horrible?)

S'il vous plaît garder à l'esprit que ADODB est horrible et a été conçu dans l'ère PHP4. S'il vous plaît envisager d'utiliser quelque chose de plus moderne, comme PDO.

+0

+1 pour connaître réellement la librairie (au lieu de googler le paramétrage comme pour xD) et recommander une meilleure alternative :) – Matchu

+0

Je n'ai jamais touché ADODB dans ma vie, j'ai recherché la méthode de liaison des paramètres bien. En fait, je préférerais votre solution, car je ne me soucie pas vraiment d'avoir à faire une préparation séparée. Croix a attribué la mention +1. ;) – Charles

+1

Je supposais que ADODB échappait aux choses automatiquement quelle que soit la méthode utilisée pour construire l'instruction. C'est * magic! * (Tm). Merci de m'avoir corrigé; J'utilise la liaison et le passage à PDO maintenant. – James

1

Je pense que la solution est beaucoup plus facile: Vous insérez l'entrée utilisateur directement, par conséquent, la ' briser votre Requête SQL (Ce est déjà une injection SQL!) Donc, vous devez échapper à ceux-ci. Mais je ne sais pas quelle méthode ADOdb fournit pour cela. C'est mysql_real_escape_string pour mysql_ et PDO::quote pour PDO.

En outre: S'il vous plaît ne pas utiliser $_REQUEST, utilisez $_POST à la place. Et même plus s'il vous plaît ne pas utiliser register_globals, ce n'est pas sûr! Utilisez $_POST à la place.

+0

J'utilise $ _REQUEST dans cette instance car il est plus facile à tester. :-) – James

2

Ce n'est pas un filtrage agressif pour empêcher l'injection SQL; c'est qu'il n'y a aucune prévention d'injection SQL ici. La citation unique dans le CSS est interprétée comme une citation unique dans la requête, provoquant une erreur de syntaxe.

Je n'ai pas utilisé ADOdb auparavant, mais il ressemble à it supports parameter binding, ce qui vous permettra de créer des requêtes plus esthétiques et de les faire fonctionner comme prévu (sans risque d'injection SQL).

$db->Execute('UPDATE foo SET bar = ?, baz = ?', array("it's", "working")); 

Comme la base de données voit, ce qui précède est équivalent à ce qui suit:

$db->Execute("UPDATE foo SET bar = 'it\'s', baz = 'working'"); 

La syntaxe est correcte, vous évitez les erreurs et l'injection, et il est beaucoup plus agréable de travailler avec, de toute façon :)

Questions connexes