10
votes

Comment nettoyer (prévenir l'injection SQL) Dynamic SQL dans SQL Server?

Nous avons une tonne de procédures stockées SQL Server qui s'appuient sur SQL dynamique.

Les paramètres à la procédure stockée sont utilisés dans une instruction SQL dynamique.

Nous avons besoin d'une fonction de validation standard dans ces procédures stockées pour valider ces paramètres et prévenir l'injection SQL.

suppose que nous avons ces contraintes:

  1. Nous ne pouvons pas réécrire les procédures pour ne pas utiliser SQL dynamique

  2. Nous ne pouvons pas utiliser sp_oacreate, etc., pour utiliser des expressions régulières pour la validation.

  3. Nous ne pouvons pas modifier l'application qui appelle la procédure stockée pour valider les paramètres avant de passer à la procédure stockée.

    existe-t-il un ensemble de caractères que nous pouvons filtrer pour nous assurer que nous ne sommes pas sensibles à l'injection SQL?


1 commentaires

Aie. Normalement, il est 3) qui devrait être modifié pour empêcher l'injection SQL. N'oubliez pas que c'est "injection SQL", pas "rejet SQL". Une fois que cela arrive à la DB, il devrait déjà être nettoyé. Mais si vous dites que vous ne pouvez pas changer l'application, je suppose que vous ne pouvez pas. Intéressé à voir les réponses.


8 Réponses :


2
votes

OWASP possède des informations sur cette stratégie. Il devrait toujours être une option de dernière fossée (comme expliqué dans l'article que je suis en train de relier), mais si c'est votre seule option ...

http://www.owasp.org/index.php/sql_inject_prevention_cheat_sheet

une citation de l'article sur le dernier option de fossé < / p>

Cependant, cette méthodologie est fragile comparé à l'utilisation paramétrée requêtes. Cette technique ne devrait être que utilisé, avec prudence, à moderniser l'héritage code de manière rentable. Applications construites à partir de zéro ou Applications nécessitant un risque faible la tolérance doit être construite ou réécrit en utilisant paramétré requêtes.

Essentiellement, l'argument contre cette approche est même si vous échappez à toutes les mauvaises intrants connues, rien ne garantit que quelqu'un ne proposera pas un moyen de le contourner dans l'avenir.

Cependant, pour répondre à votre question spécifiquement ...

Une liste de caractères à échapper est dans l'article que j'ai lié ci-dessus.

Modifier Comme indiqué, l'article ne fournit pas de très bons liens. Toutefois, pour SQL Server, celui-ci fait: http://msdn.microsoft.com /en-us/library/ms161953.cax

Notez que la liste des caractères que vous devez échapper variera à la base de la plate-forme DB, mais on dirait que vous utilisez SQL Server, Cela devrait donc être pertinent ..

Devis de l'article ci-dessous:

L'entrée de filtrage peut également être utile pour protéger contre l'injection SQL en supprimant les caractères d'évacuation. Cependant, en raison du grand nombre de caractères pouvant poser des problèmes, ce n'est pas une défense fiable. L'exemple suivant recherche pour le délimiteur de chaîne de caractères. xxx

comme des clauses

Notez que si vous utilisez une clause similaire, les caractères génériques doivent toujours être échappés : xxx


1 commentaires

-1: L'article ne dit pas quels caractères s'échapper pour MS SQL Server. Il s'agit simplement de liens vers un autre article qui ne rend pas évident que les personnages s'échappent.



3
votes

C'est un problème vraiment méchant, son pas un problème que vous souhaitez résoudre, mais voici un cas trivial qui fonctionne (des critiques, faites-moi savoir si j'ai raté un cas, cette Livré avec no garanties) xxx


4 commentaires

+1, je n'ai jamais rien vu pour suggérer que cela ne fonctionne pas.


À mon avis, exécutez toute SQL dynamique à l'aide de rien d'autre que SP_EXecutesQL avec toutes les valeurs transmises car les paramètres sont simplement puce de faute professionnelle.


Toujours vulnérable. Supposons que le corps de notasbad contienne ce qui suit: Set @sql = N'Select * de '+ @ Safeish .... Si l'utilisateur peut deviner le nom d'une table, ils peuvent soumettre @param =' Tablename; Drop Base de base de données XYZ; - '


@Frankadelic Cela fonctionne bien pour le cas trivial, bien sûr, selon votre contexte, vous devez échapper à SQL de différentes manières, d'où l'avertissement contre cela, je suis d'accord avec @km, en général, c'est quelque chose comme ça est une mauvaise idée et pas un problème que vous voulez avoir à résoudre



12
votes

Je crois qu'il y a trois cas différents que vous devez vous soucier de:

  • cordes (tout ce qui nécessite des devis): '' '+ remplacer (@string,' '' '' + '' '', '' '' '') + '' '' Code> LI>
  • noms (quoi que ce soit où des citations ne sont pas autorisées): quotename (@string) code> li>
  • choses qui ne peuvent pas être citées: cela nécessite de blanchir li> ul>

    note forte>: tout em> dans une variable de chaîne ( char code>, varchar code>, nchar code>, nvarchar code>, etc.) provenant de sources contrôlées par l'utilisateur doit utiliser l'une des méthodes ci-dessus. Cela signifie que même des choses que vous attendez d'être citées sont citées si elles sont stockées dans des variables de chaîne. P>

    Pour plus de détails, voir la Microsoft Magazine Strike> (Lien obsolète: 2016-10-19) SUB>. P>.

    Voici un exemple en utilisant les trois méthodes: p>

    EXEC 'SELECT * FROM Employee WHERE Salary > ''' +
         REPLACE(@salary, '''', '''''') +   -- replacing quotes even for numeric data
         ''' ORDER BY ' + QUOTENAME(@sort_col) + ' ' +  -- quoting a name
         CASE @sort_dir WHEN 'DESC' THEN 'DESC' END     -- whitelisting
    


1 commentaires

Je suis d'accord ici, cela dépend totalement de ce que SQL est construit



6
votes

Les cas triviaux peuvent être corrigés par quotename < / a> et remplacer: xxx

Bien que le nom de quotidien puisse également être utilisé sur les littéraux pour ajouter les guillemets simples et remplacer des guillemets simples avec des guillemets simples doubles, car il tronque l'entrée à 128 caractères. Recommandé.

Mais ce n'est que la pointe de l'iceberg. Il y a des noms multipart ( dbo.table ) Vous devez prendre soin de: citer le multipartaname entraînerait un identifiant non valide [dbo.table] , il doit être analysé et divisé (en utilisant Paysename ), puis correctement cité dans [dbo]. [Table] .

Un autre problème est une troncature, ce qui peut arriver même si vous faites le remplacement trivial sur les littéraux, voir Nouvelles attaques de troncature SQL et comment les éviter .

Le problème de l'injection SQL ne peut jamais être résolu avec une seule fonction magique placée à chaque procédure. C'est comme demander "Je veux une fonction qui rendra mon code plus rapide". Empêcher les attaques d'injection est et jeu de bout en bout qui nécessite un codage de discipline tout au long de , il ne peut pas être simplement ajouté comme une réflexion après coup. Votre meilleure chance est d'inspecter chaque procédure et d'analyser le code T-SQL ligne-ligne , avec un œil ouvert pour les vulnérabilités, puis corrigez les problèmes que vous les trouvez. < / p>


2 commentaires

Je recommande pas en utilisant parsename car il est destiné à être utilisé sur des noms déjà cités. Si votre utilisateur vous dit, il souhaite obtenir des données à partir de secrète..table vous souhaitez interroger contre [secret..table] et obtenir une erreur. Vous ne voulez pas qu'il puisse interroger [secret] .. [table] !


À mon avis, exécutez toute SQL dynamique à l'aide de rien d'autre que SP_EXecutesQL avec toutes les valeurs transmises car les paramètres sont simplement puce de faute professionnelle.



0
votes

Pouvez-vous obtenir SQL CLR peut être d'excellente utilisation - vous pouvez au moins l'utiliser pour écrire beaucoup, une assassination beaucoup plus efficace que celle que l'on peut utiliser en T-SQL. Dans un monde perfacteur, vous pouvez remplacer complètement les processus stockés avec des déclarations paramétrées et d'autres structures plus fortes.


1 commentaires

Malheureusement, je ne peux pas utiliser CLR en raison de restrictions DBA



4
votes

Avec ces contraintes, vous êtes assez vissé.

Voici une deux options qui pourraient vous donner une certaine direction:

  1. Utilisez le validateur / analyseur de liste blanche qui n'acceptent que les requêtes qui sont dans un format et avec des mots-clés et des tables attendues. Cela fonctionnera probablement uniquement avec un très bon analyseur SQL qui comprend vraiment la syntaxe.

  2. exécuter des requêtes dans un environnement restreint. Par exemple, utilisez un compte d'utilisateur avec des droits très limités. Par exemple, n'autorise que (lire) l'accès à certaines vues qui ne reviendront jamais de données sensibles et interdisent l'accès à toutes les autres vues, toutes les procédures, les fonctions et les tables stockées. Même plus sûr consiste à exécuter ces requêtes sur un autre serveur de base de données. N'oubliez pas non plus de désactiver le Commande OpenRowset .

    Veuillez noter les suivants:

    1. Lorsque vous acceptez toutes les requêtes, à l'exception de ceux qui ont des mots-clés non valides, vous échouerez certainement, car la liste noire échoue toujours. Surtout avec une langue aussi compliquée comme SQL.

    2. N'oubliez pas que, permettant à SQL dynamique de sources que vous ne pouvez pas faire confiance, c'est le mal dans son sens pur, même lorsque vous utilisez ces conseils, car une fois dans un moment Bugs sont découverts qui peuvent être abusés en envoyant une SQL spécialement conçue sur un serveur. Par conséquent, même si vous appliquez ces conseils, le risque est toujours là.

    3. Lorsque vous décidez d'aller avec une solution qui permet à SQL dynamique. S'il vous plaît, ne pensez pas que vous puissiez vous proposer une solution sûre, surtout si vous essayez de protéger les données commerciales sensibles. Embauchez un spécialiste de la sécurité du serveur de base de données pour vous aider à vous aider.


0 commentaires

-1
votes

Il existe une autre approche qui peut-elle fonctionner éventuellement , bien que cela dépend de quels caractères sont autorisés dans les paramètres de la procédure stockée. Au lieu d'échapper aux caractères gênants pouvant être utilisés pour l'injection SQL, supprimez plutôt les caractères. Par exemple, si vous avez ce sp: xxx

Vous pouvez remplacer toutes les guillemets avec des espaces ou avec une chaîne vide. Cette approche peut également être utilisée pour remplacer des caractères de commentaire tels que / * * / - en utilisant plus de commandes Remplacer (comme je viens de montrer ci-dessus). Mais notez que cette approche ne fonctionnera que si vous ne vous attendez jamais à ces caractères en entrée normale, ce qui dépend de votre application.

Remarque L'ensemble des caractères remplacés est basé sur https://msdn.microsoft.com/en-us/library/ms161953 (SQL.105). ASPX


6 commentaires

L'injection SQL n'est pas appelée une "injection de devis unique". Pour une raison.


Je ne connais pas la «injection de devis unique», la technique que je viens de décrire est une méthode de protection contre l'injection SQL et elle est basée sur l'article Microsoft que j'ai référencé ci-dessus. Je ne suis pas clair pourquoi vous avez fait voté cette réponse.


Je tiens toujours à en apprendre davantage sur la sécurité et j'accueillerais votre explication de la recommandation de Microsoft dans msdn.microsoft.com/en-us/library/ms161953 (SQL.105) .aspx est" délibérément imparfait ".


Étant donné que cette recommandation était utilisée sur ce site par exemple, vous seriez Impossible de poster votre réponse du tout.


Encore une fois, j'essaie de comprendre ici - est-ce votre point de vue que la recommandation de Microsoft est pathétique? Pour moi, cela semblait une approche qui pourrait aider la question initiale, tenant compte de toutes les contraintes qu'ils ont énumérées dans la question.


En outre, cela n'empêche pas l'injection SQL. Cela pourrait compliquer l'exploit, mais il n'a absolument rien à voir avec l'injection elle-même.



3
votes

existe-t-il un ensemble de caractères que nous pouvons filtrer pour nous assurer que nous ne sommes pas sensibles à l'injection SQL?

NO

Injection SQL n'est pas appelé "Certains jeu d'injection de caractères", et pour une raison. Filtrer certains caractères pourrait compliquer l'exploitation particulière, mais n'empêche pas l'injection SQL elle-même. à exploiter une injection SQL il faut écrire SQL. Et SQL ne se limite pas à peu de caractères spéciaux.


0 commentaires