web-dev-qa-db-fra.com

Puis-je paramétrer le nom de la table dans une instruction préparée?

J'ai utilisé la fonction mysqli_stmt_bind_param à plusieurs reprises. Cependant, si je sépare les variables que j'essaie de protéger contre l'injection SQL, je rencontre des erreurs.

Voici un exemple de code:

function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol )
{
    $statement = $mysqli->prepare("INSERT INTO " .$new_table . " VALUES (?,?,?,?,?,?,?);");
    mysqli_stmt_bind_param( $statment, 'sssisss', $Partner, $Merchant, $ips, $score, $category, $overall, $protocol );
    $statement->execute();
}

Est-il possible de remplacer en quelque sorte la concaténation .$new_table. par une autre instruction de point d'interrogation, de créer une autre instruction de paramètre bind ou d'ajouter sur celle existante une protection contre l'injection SQL?

Comme ceci ou une forme de ceci:

function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol )
{    
    $statement = $mysqli->prepare("INSERT INTO (?) VALUES (?,?,?,?,?,?,?);");
    mysqli_stmt_bind_param( $statment, 'ssssisss', $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol );
    $statement->execute();
}
51
GK1667

La réponse courte à votre question est "non".

Au sens strict, au niveau de la base de données, les instructions préparées ne permettent de lier les paramètres que pour les bits "valeurs" de l'instruction SQL.

Une façon de penser à ceci est "des choses qui peuvent être substituées lors de l'exécution de l'instruction sans modifier son sens". Le nom de la table ne fait pas partie de ces valeurs d’exécution, car il détermine la validité de l’instruction SQL elle-même (c’est-à-dire quels noms de colonnes sont valides) et sa modification au moment de l’exécution modifierait potentiellement la validité de l’instruction SQL.

À un niveau légèrement supérieur, même dans les interfaces de base de données émulant la substitution de paramètres d’instruction préparée plutôt que d’envoyer des instructions préparées à la base de données, telles que PDO, qui pourraient éventuellement vous permettre d’utiliser un espace réservé n’importe où (étant donné que cet espace réservé est remplacé la base de données dans ces systèmes), la valeur de l’espace réservé à la table serait une chaîne et elle-même incluse dans le code SQL envoyé à la base de données, donc SELECT * FROM ? avec mytable car le paramètre finirait par envoyer SELECT * FROM 'mytable' à la base de données, qui est invalide SQL.

Votre meilleur pari est juste de continuer avec 

SELECT * FROM {$mytable}

mais vous absolument devriez avoir une liste blanche de tables que vous vérifiez en premier si ce $mytable provient d'une entrée utilisateur.

68
Sam Graham

(Réponse tardive, consultez ma note de côté).

La même règle s'applique lorsque vous essayez de créer une "base de données".

Vous ne pouvez pas utiliser une instruction préparée pour lier une base de données.

C'est à dire.:

CREATE DATABASE IF NOT EXISTS ?

ne fonctionnera pas. Utilisez plutôt une liste de sécurité.

Note latérale: J'ai ajouté cette réponse (en tant que wiki de communauté) car il était souvent utilisé pour fermer des questions avec, lorsque certaines personnes posaient des questions similaires à celles-ci en essayant de lier une base de données et non un tableau et/ou colonne.

1
Funk Forty Niner