2009-06-10 7 views
13

J'utilise actuellement Zend_Db pour gérer mes requêtes. J'ai écrit code déjà que préformes requêtes comme celle ci-dessous:Éviter les injections MySQL avec la classe Zend_Db

$handle->select()->from('user_id') 
        ->where('first_name=?', $id) 
        ->where('last_name=?', $lname) 

Je l'ai fait sans désinfectante l'entrée, en supposant Zend_Db sera. Est-ce que Zend fait ça?

Une autre question: Est-ce que Zend_Db désinfecte insert('table', $data) et update?

Merci.

Répondre

24

j'ai écrit beaucoup de code pour les paramètres de base de données et citant en Zend Framework alors que j'étais le chef d'équipe du projet (jusqu'à la version 1.0).

J'ai essayé d'encourager les meilleures pratiques lorsque c'était possible, mais j'ai dû trouver un équilibre avec la facilité d'utilisation.

Notez que vous pouvez toujours examiner la valeur de chaîne d'un objet Zend_Db_Select, pour voir comment il a décidé de faire des citations.

print $select; // invokes __toString() method 

vous pouvez également utiliser le Zend_Db_Profiler pour inspecter le SQL qui est exécuté en votre nom par Zend_Db.

$db->getProfiler()->setEnabled(true); 
$db->update(...); 
print $db->getProfiler()->getLastQueryProfile()->getQuery(); 
print_r $db->getProfiler()->getLastQueryProfile()->getQueryParams(); 
$db->getProfiler()->setEnabled(false); 

Voici quelques réponses à vos questions spécifiques:

  • Zend_Db_Select::where('last_name=?', $lname)

    Les valeurs sont citées de manière appropriée. Bien que le "?" ressemble à un espace réservé de paramètre, dans cette méthode, l'argument est réellement cité de manière appropriée et interpolé. Ce n'est donc pas un vrai paramètre de requête. En fait, les deux affirmations suivantes produisent exactement la même requête que l'utilisation ci-dessus:

    $select->where($db->quoteInto('last_name=?', $lname)); 
    $select->where('last_name=' . $db->quote($lname)); 
    

    Cependant, si vous passez un paramètre qui est un objet de type Zend_Db_Expr, alors il est pas cité. Vous êtes responsable des risques d'injection SQL, parce qu'il est interpolé textuellement, pour soutenir les valeurs d'expression:

    $select->where('last_modified < ?', new Zend_Db_Expr('NOW()')) 
    

    Toute autre partie de cette expression qui doit être cité ou délimité est de votre responsabilité. Par exemple, si vous interpolez des variables PHP dans l'expression, la sécurité est de votre responsabilité. Si vous avez des noms de colonnes qui sont des mots-clés SQL, vous devez les délimiter vous-même avec quoteIdentifier(). Exemple:

    $select->where($db->quoteIdentifier('order').'=?', $myVariable) 
    
  • Zend_Db_Adapter_Abstract::insert(array('colname' => 'value'))

    Nom de la table et les noms de colonnes sont délimitées, sauf si vous désactivez AUTO_QUOTE_IDENTIFIERS.

    Les valeurs sont paramétrées en tant que vrais paramètres de requête (non interpolés). A moins que la valeur ne soit un objet Zend_Db_Expr, auquel cas il est interpolé verbatim, donc vous pouvez insérer des expressions ou NULL ou autre.

  • Zend_Db_Adapter_Abstract::update(array('colname' => 'value'), $where)

    Nom de la table et les noms de colonnes sont délimitées, sauf si vous désactivez AUTO_QUOTE_IDENTIFIERS.

    Les valeurs sont paramétrées, sauf si elles sont des objets Zend_Db_Expr, comme dans la méthode insert().

    L'argument $where n'est pas filtré du tout, vous êtes donc responsable des risques d'injection SQL dans celui-ci. Vous pouvez utiliser la méthode quoteInto() pour faciliter la citation.

+0

Grande réponse, Bill, et un excellent composant tout autour :) –

+0

Si vous utilisez la fonction 'insert()' sur une instance de 'TableGateway', l'échappement des colonnes avec des noms réservés est automatiquement fait pour vous comme indiqué dans la deuxième puce ci-dessus. Si vous l'échappez manuellement (c'est-à-dire (SQL Server) 'array ([from] => 1));' il génère une erreur de base de données indiquant que '[from]' 'est un nom de colonne invalide. Cette colonne a peut-être été échappée deux fois en tant que [[de]] ' –

1

Le morceau qui devrait vous faire sentir en sécurité est le? marques dans les clauses where. Ce sont des paramètres qui sont remplacés en toute sécurité par le second argument du système de base de données.

+1

ce n'est pas le point. sprintf utilise? marques aussi bien. – erenon

+0

Oui, je voulais dire par rapport aux appels de méthode Zend_Db –

1

Lorsque vous avez besoin à un autre endroit (comme dans rejoindre) ou vous ne savez pas si elle sera échappé alors vous pouvez toujours utiliser $this->getAdapter()->quoteInto('type = ?',1);

2

par défaut lorsque vous utilisez la valeur de liaison dans vos requêtes SQL comme ceci:

where('first_name=?', $id); 

Zend_Db utilise des guillemets appropriés pour empêcher l'injection SQL. Bien qu'il soit fortement recommandé (par des livres, des articles, des manuels et des expériences personnelles) de désinfecter/filtrer les entrées des utilisateurs. Zend_Filter peut être très utile.

0

Le filtrage d'entrée est toujours bon, car il ira probablement ailleurs que dans la base de données, et vous aurez au moins besoin de données saines dans votre base de données à un certain niveau.

  • Zend_Filter_Input sur la manière
  • déclarations préparées (ou quoteInto sinon dans un prêt)
  • filtres d'échappement sur la sortie (htmlentities, etc.).
0

Une chose à ce sujet, lorsque la valeur est NULL, vous pouvez ACHIVE pas requête valide

$value = NULL; 
$select->where('prop=?', $value); 

Résultat: erreur SQL

+0

En SQL, vous ne pouvez pas utiliser l'opérateur = pour comparer à NULL de toute façon. –

+0

mon exemple ne concerne pas les valeurs NULL, j'essaie de montrer que dans certains cas vous avez besoin de vérifier/convertir le type de valeurs à transmettre dans sql-query, c'est dans le contexte de la discussion – duganets

Questions connexes