PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 06/11/2018 17:14:22

ramirez22
Membre

Se prémunir des injections SQL

Bonjour,


J'ai bien saisi le risque des injections SQL et évidemment, je voudrais m'en prémunir.
J'ai commencé à chercher un peu sur le Net, mais ma "jeunesse" (c'est une notion toute relative big_smile ) en SQL me limite.
Bref, j'ai vu qu'en fonction de certains langage, il était possible de faire des requêtes paramétrées.


Pas de bol, je développe sous WINDEV et il semblerait que je ne puisse "que" envoyer des requêtes "classiques".
J'ai tenté de créer des fonctions, mais je suis toujours vulnérable lors du

SELECT * FROM mafonction(valeurs);

puisqu'il suffit de terminer une valeur avec un

'; injection SQL ; --

pour pouvoir prendre le contrôle sur la base.


J'ai bien 2 pistes pour améliorer la sécurité :
1 - faire une analyse de chaque champs de saisie et de transformer les ' en ''. Il ne me restera plus qu'à vérifier que le caractère d'échappement \ soit bien inactif (ou alors, le gérer également dans la mise en forme)
2 - utiliser les guillemets $$. Sachant que les balises peuvent comporter des valeurs entre les 2 $, cela laisse un sacré nombre de possibilités. D'autant plus qu'il est également envisageable d'utiliser un générateur de nombre aléatoire pour les balises.
Exemple :

SELECT * FROM matable WHERE colonne1 = $1234$chaine$1234

Par contre, est-ce qu'en cas d'erreur de requête, le message d'erreur renvoyé indique en clair les balises utilisées ? Du coup, dans ce cas, les $$ perdent toute utilité.
3 - Autre solution ?


Bref, est-ce que vous avez une idée pour m'aider à sécuriser mes requêtes SVP ?


Merci de votre attention.


Cordialement, Ramirez22

Hors ligne

#2 07/11/2018 10:34:25

arthurr
Membre

Re : Se prémunir des injections SQL

Bonjour,

Jetez un oeil sur le "PREPARE" : https://docs.postgresql.fr/9.6/sql-prepare.html

Hors ligne

#3 07/11/2018 13:49:23

ramirez22
Membre

Re : Se prémunir des injections SQL

Bonjour et merci de la réponse.


Malgré tout, n'y a t'il pas possibilité d'injection (sauf erreur d'interprétation de ma part) ?


Petit exemple simple:

PREPARE recherche(text) AS SELECT * FROM matable WHERE colonne1= $1;

Il n'y a pas de risque pour la préparation puisque aucune valeur saisie par l'utilisateur n'est utilisée

EXECUTE recherche(maVariableContenantLaSaisieUtilisateur);

Si la variable contient : '%');DELETE FROM matable *; --' n'y a t'il pas de risque que la requête reçue par le serveur corresponde à :

EXECUTE recherche('%');DELETE FROM matable *; -- (tout ce qui suit n'a pas d'importance puisque considérée comme commentaire)

Cordialement,
Ramirez22

Hors ligne

#4 07/11/2018 15:17:34

gleu
Administrateur

Re : Se prémunir des injections SQL

Il faut faire un appel à quote_literal dans ce cas. Cela donnerait :

EXECUTE recherche(quote_literal(maVariableContenantLaSaisieUtilisateur));

(ce qui peut aussi se faire directement sur la première requête, sans passer par un PREPARE)


Guillaume.

Hors ligne

#5 07/11/2018 17:49:57

dverite
Membre

Re : Se prémunir des injections SQL

Bref, j'ai vu qu'en fonction de certains langage, il était possible de faire des requêtes paramétrées.

Dans WinDev aussi visiblement. Si je cherche "windev requêtes sql paramétrées" dans google et le 1er résultat est:
https://doc.pcsoft.fr/?2032050

avec ce style d'exemple:

SELECT * FROM CLIENT WHERE NOM = {Param1} AND PRENOM = {Param2}

HExécuteRequête(REQ_Clients_nom_prénom, hRequêteDéfaut, ...
"Dupond", "Jean")


Si vous ne voulez pas utiliser le système de Windev, il faut effectivement faire votre propre fonction d'échappement, l'équivalent du PQescapeLiteral () de la bibliothèque libpq (en C), ou du quote_literal() côté serveur.

Vous avez raison de remarquer que EXECUTE(paramètres) présente exactement  le même risque qu'appeler une requête non préparée avec les mêmes paramètres. L'affirmation que requête préparée = protection contre les injections SQL est une sur-simplification. En réalité, si on utilise mal les requêtes préparées on est tout aussi vulnérable, et à l'inverse si on construit sa requête SQL avec des paramètres injectés mais en respectant à 100% les règles de syntaxe, il y a zéro risque avec les entrées malveillantes.

Hors ligne

#6 07/11/2018 20:19:18

ramirez22
Membre

Re : Se prémunir des injections SQL

Merci de votre aide à tous.

gleu a écrit :

Il faut faire un appel à quote_literal dans ce cas. Cela donnerait :

EXECUTE recherche(quote_literal(maVariableContenantLaSaisieUtilisateur));

(ce qui peut aussi se faire directement sur la première requête, sans passer par un PREPARE)

J'y ai vraiment cru big_smile


Hélas, lorsque je fais, par exemple :

EXECUTE recherche(quote_literal(maVariable));

Si je mets maVariable = bla

Je me retrouve avec une erreur car maVariable est remplacée par la valeur (normal) sans quote, donc erreur de postgreSQL : column "bla" does not exist at character ...

Si je mets maVariable = 'bla'

Je me retrouve sans erreur PostgreSQL, mais mes valeurs enregistrées sont fausse : un SELECT me retourne la valeur 'bla' (avec les quote).

EXECUTE recherche(quote_literal('maVariable'));

ou

set mavariable = 'bla'     <= (Ce n'est qu'une représentation de l'affectation de mavariable)
EXECUTE recherche(quote_literal(maVariable));

SELECT * FROM matable
'bla'

Je pourrais par contre utiliser le $$ (je n'ai pas fait ce test).
[EDIT] Je viens de réaliser le test, les $$ sont remplacés par des '' et mes valeurs sont encadrées par un '... Dommage

dverite a écrit :

Si vous ne voulez pas utiliser le système de Windev,

Exact, je ne veux pas utiliser le moteur HFSQL (système de PCSOFT / WINDEV) : il met des guillemets (") à chaque terme (les noms de colonnes, les valeurs...), il faut saisir la base de donnée sous l'outil WINDEV (double de boulot) + d'autres joyeusetés de ce genre.
Il est très bien quand on reste sous le système HFSQL client/serveur, mais je le trouve peu pratique lorsqu'on le fait causer avec PostgreSQL (certes il est possible de forcer la non correction des requêtes, mais ça commence à faire un peu beaucoup de manip'). De plus, je n'ai pas le choix dans la base de donnée (postgreSQL only dixit ma boite). Enfin, HFSQL a à priori quelques problèmes de sécurité et mon application est 'sensible'.


Je crois que je vais essayer de créer ma propre fonction d'échappement en m'inspirant de PQescapeLiteral(). Ça va demander un peu de boulot, mais je pense que la sécurité des requêtes SQL le vaut bien big_smile


Merci de vos interventions, si vous voyez d'autres pistes, je suis toujours curieux smile

Bonne soirée à toutes/tous
Ramirez22

Dernière modification par ramirez22 (07/11/2018 20:31:34)

Hors ligne

#7 14/11/2018 18:59:01

ramirez22
Membre

Re : Se prémunir des injections SQL

Bonjour,


Histoire de "terminer" ce Post et au cas où quelqu'un chercherait la même chose, voilà la procédure que j'ai créé sous Windev pour réaliser la fonction de doubler les quote automatiquement.
J'en ai profité pour supprimer les quotes multiples, afin de ne pas les doubler inutilement.

PROCEDURE Quote(sValeur est une chaîne)
i,j sont des entiers 
i = 1
sChaineEntree, sChaineSortie sont des chaînes
sChaineEntree = sValeur
TANTQUE i <= Taille(sChaineEntree)
	SI sChaineEntree[[i]] = "'" ALORS 				// si le caractère n'est pas un quote, on passe
		j = i + 1
		SI sChaineEntree[[j]] = "" ALORS			// si le caractère suivant est vide, c'est qu'on arrive à la fin de la chaine
			sChaineSortie += sChaineEntree[[i]] 	        // on complète celle-ci
			GOTO suite					// et on passe à la phase de doublement des quote
		FIN
		TANTQUE j <= Taille(sChaineEntree)			// par contre, si le caractère suivant n'est pas vide
			SI sChaineEntree[[i]] = sChaineEntree[[j]] ALORS	// on vérifie que ce n'est pas un quote aussi
				j++						// dans l'affirmative, on passe au caractère suivant
			SINON						// sinon le quote est unique
				sChaineSortie += sChaineEntree[[i]]		// il est donc mis dans la chaine de sortie
				i=j						// et on passe au caractère suivant
				SORTIR						// (on passe directement au caractère non quote suivant)
			FIN
			SI j > Taille(sChaineEntree) ALORS		// on vérifie si on est à la fin de la chaine
				sChaineSortie += sChaineEntree[[i]] 	// si oui,on complète celle-ci
				GOTO suite				// et on passe à la phase de doublement des quote
			FIN
		FIN
	SINON								// le caractère n'est pas un quote (voir + haut)
		sChaineSortie += sChaineEntree[[i]]			// il est donc inscrit dans la chaine de sortie
		i++
	FIN
FIN

suite:
// Doublement des quote restantes pour qu'elles soient prises en compte comme caractère (et non comme fin de chaine)
sChaineSortie = Remplace(sChaineSortie,"'","''")

RENVOYER sChaineSortie

Évidemment, n'étant pas codeur professionnel, il y a sasns doute mieux à faire mais j'assume big_smile


Merci à tous de votre aide!
Bonne soirée.

Hors ligne

Pied de page des forums