73 votes

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 utilisateur, je l'échappe et je la transmets à l'API. L'entrée utilisateur est assez simple. Elle demande les valeurs des colonnes. Par exemple :

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 des colonnes ?

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

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

124voto

Seva Alekseyev Points 31812

Comme l'utilisation de SqlParameter n'est pas possible, il suffit de remplacer ' par '' (c'est-à-dire deux guillemets simples, et non un guillemet double) dans les chaînes de caractères. C'est tout.

À tous ceux qui voudraient me descendre : relisez la première ligne de la question. "Utiliser des paramètres" était aussi ma réaction instinctive.

EDIT : oui, je suis au courant des attaques par injection SQL. Si vous pensez que cette citation est vulnérable à celles-ci, veuillez fournir un contre-exemple fonctionnel. Je pense que ce n'est pas le cas.

0voto

ThurstonFord Points 1

J'utilisais le sql dynamique (j'entends le peloton d'exécution charger ses fusils) pour la fonctionnalité de recherche, mais il se cassait dès qu'un utilisateur cherchait quelqu'un avec un nom de famille comme "O'Reilly".

J'ai réussi à trouver une solution de contournement (lire "hack") :

J'ai créé une fonction scalaire dans sql qui remplace un guillemet simple par deux guillemets simples, ce qui permet d'échapper au guillemet simple en question.
"...Nom de famille LIKE '%O'Reilly%' AND..." devient "...Nom de famille LIKE '%O''Reilly%' AND..."

Cette fonction est appelée à partir de sql chaque fois que je soupçonne que des champs peuvent contenir un caractère guillemet simple, par exemple : prénom, nom de famille.

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

Ce n'est pas très élégant ou efficace, mais ça marche quand on est à court d'argent.

0voto

On peut souhaiter remplacer ' par '' au lieu de paramétrer lorsqu'on a besoin de traiter le problème ' dans une grande quantité de sql ad hoc en peu de temps avec un risque minimal de rupture et un minimum de tests.

0voto

Todd Points 2386

Utilisation de SqlCommand et d'Entity Framework exec sp_executesql... .

Il existe donc une véritable alternative aux chaînes brutes avec votre propre modèle 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.

Donc, même si votre code n'empêche pas l'injection SQL, la réponse ultime est sp_executesql et non SqlCommand.

Cela dit, je suis sûr qu'il existe des exigences de manipulation particulières pour la génération d'une chaîne de caractères protégée contre les injections SQL qui utilise sp_executesql.

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

-4voto

Marc Gravell Points 482669

Simple :

const string sql = "SELECT * FROM SOME_TABLE WHERE Name = @name";

et ajoutez le @name avec une valeur :

cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@name", name);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X