Les procédures stockées n'empêchent pas, comme par magie, l'injection SQL, mais elles le facilitent grandement. Tout ce que vous avez à faire est quelque chose comme ceci (exemple Postgres):
CREATE OR REPLACE FUNCTION my_func (
IN in_user_id INT
)
[snip]
SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]
C'est ça! Le problème ne se pose que lors de la création d'une requête via la concaténation de chaînes (c-à-d. SQL dynamique), et même dans ces cas, vous pourrez peut-être lier! (Dépend de la base de données.)
Comment éviter l'injection SQL dans votre requête dynamique:
Étape 1) Demandez-vous si vous avez vraiment besoin d’une requête dynamique. Si vous assemblez des chaînes simplement pour définir l'entrée, vous le faites probablement mal. (Il existe des exceptions à cette règle. Une exception concerne la création de requêtes sur certaines bases de données. Vous risquez d'avoir des problèmes de performances si vous ne l'obligez pas à compiler une nouvelle requête à chaque exécution. Mais recherchez ce problème avant de vous lancer. )
Étape 2) Recherchez le moyen approprié de définir la variable pour votre SGBDR particulier. Par exemple, Oracle vous permet d'effectuer les opérations suivantes (en citant leurs documents):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Ici, vous ne concaténez toujours pas l’entrée. Vous vous engagez en toute sécurité! Hourra!
Si votre base de données ne prend pas en charge quelque chose comme ce qui précède (espérons qu'aucun d'entre eux ne l'est encore, mais je ne serais pas surpris) - ou si vous devez toujours concaténer votre entrée (comme dans le cas "parfois" de requêtes de rapports comme J'ai fait allusion à ci-dessus), alors vous devez utiliser une fonction d'échappement appropriée. Ne l'écris pas toi-même. Par exemple, postgres fournit la fonction quote_literal (). Donc vous courriez:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
De cette façon, si in_name est quelque chose de sournois comme '[snip] ou 1 = 1' (la partie "ou 1 = 1" signifie que toutes les lignes sont sélectionnées, permettant ainsi à l'utilisateur de voir les salaires qu'il ne devrait pas!), Puis quote_literal enregistre vos fesses par faire la chaîne résultante:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
Aucun résultat ne sera trouvé (sauf si vous avez des employés avec des noms vraiment bizarres.)
C'est l'essentiel! Permettez-moi maintenant de vous laisser avec un lien vers un article classique du gourou d'Oracle, Tom Kyte, sur le sujet de l'injection SQL, pour faire passer le message: Linky