web-dev-qa-db-fra.com

Comment échapper à des requêtes SQL simples en C # pour SqlServer

J'utilise une API qui attend une chaîne SQL. Je prends une entrée d'utilisateur, échappez-la et transmettez-la à l'API. La saisie de l'utilisateur est assez simple. Il demande des valeurs de colonne. Ainsi:

string name = userInput.Value;

Ensuite, je construis une requête SQL:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           name.replace("'", "''"));

Est-ce assez sûr? Si ce n'est pas le cas, existe-t-il une fonction de bibliothèque simple qui sécurise les valeurs de colonne:

string sql = string.Format("SELECT * FROM SOME_TABLE WHERE Name = '{0}'",
                           SqlSafeColumnValue(name));

L'API utilise SQLServer comme base de données. 

67
sc45

Puisque l'utilisation de SqlParameter n'est pas une option, remplacez simplement 'par' '(c'est-à-dire deux guillemets simples, pas un guillemet double) dans les chaînes de caractères. C'est tout.

Pour les votants descendants: relisez la première ligne de la question. "Utiliser les paramètres" était aussi ma réaction instinctive.

EDIT: oui, je connais les attaques par injection SQL. Si vous pensez que cette citation est vulnérable, veuillez fournir un contre-exemple qui fonctionne. Je pense que ce n'est pas.

108
Seva Alekseyev

Il est préférable d’utiliser des paramètres SQL, mais vous avez alors une limite de 2300 paramètres pour la requête. Dans la plupart des cas, cela sera plus que suffisant. Mais dans de rares cas, lorsque vous dépassez cette limite, je vois cela comme une option.

0
charino

On peut souhaiter remplacer «par» au lieu de paramétrer lorsque le problème doit être résolu dans une grande quantité de sql ad hoc en peu de temps, avec un risque minimal de bris et de tests.

0
Alex

SqlCommand et Entity Framework utilisent exec sp_executesql...

Il existe donc vraisemblablement une alternative aux chaînes brutes avec votre propre motif d'échappement. Avec SqlCommand, vous utilisez techniquement des requêtes paramétrées, mais vous contournez l’abstraction ADO.Net du code SQL sous-jacent. 

Ainsi, bien que votre code n'empêche pas l'injection SQL, la réponse ultime est sp_executesql et non pas SqlCommand. 

Cela dit, je suis sûr qu'il existe des exigences de traitement particulières pour la génération d'une chaîne protégée contre l'injection SQL utilisant sp_executesql.

voir: Comment renvoyer des valeurs d'une procédure stockée SQL dynamique vers Entity Framework?

0
Todd

J'utilisais SQL dynamique (j'entendais le peloton charger ses armes) pour la recherche, mais la lecture s'arrêtait à chaque fois qu'un utilisateur cherchait quelqu'un avec un nom de famille comme "O'Reilly". 

J'ai réussi à trouver un moyen de contourner le problème (lire "bidouille"):

Création d'une fonction à valeur scalaire dans SQL qui remplaçait une citation unique par deux guillemets simples, échappant ainsi à la citation simple incriminée.
"... Nom de famille LIKE '% O'Reilly%' AND ..." Devient "... comme LIEN '% O''Reilly%' AND ..."

Cette fonction est appelée à partir de SQL chaque fois que je soupçonne que les champs peuvent contenir un seul caractère de guillemet, à savoir: prénom, nom.

CREATE FUNCTION [dbo].[fnEscapeSingleQuote]
    (@StringToCheck NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    DECLARE @Result NVARCHAR(MAX)
    SELECT @Result = REPLACE(@StringToCheck, CHAR(39), CHAR(39) + CHAR(39))
    RETURN @Result
END

Pas très élégant ni efficace, mais ça marche quand on est pincé.

0
ThurstonFord