Utiliser des requêtes SQL paramétrées
Il m’arrive de temps en temps durant mon travail de ne pas pouvoir créer ou convertir mais simplement de devoir « améliorer » du code. Dans certaines situations, ce mot m’agace particulièrement surtout lorsqu’il s’accompagne de phrases du genre « tu te souviens de l’application développée l’année passée ? ».
Cela m’est arrivé la semaine passée : je devais améliorer le mécanisme d’authentification d’une application ASP. J’ai effectué pas mal de développement en ASP ces dernières années mais très peu de pro qui jets différents professionnellement parlant. Je lis régulièrement de la littérature traitant de la sécurité informatique mais il y a toujours eu un énorme fossé entre ce que le travail permet de faire pour des raisons de délais ou de politique et ce qui devrait vraiment être fait en matière de l’est sécurité.
Cette modification était mineure. J’ai donc décidé d’en profiter pour faire quelque chose d’intéressant et d’une sécurité accrue : utiliser des requêtes SQL paramétrées. La raison principale pour laquelle je voulais utiliser cette technique est de fortement réduire les risques d’injection de type SQL durant le processus d’authentification.
Les requêtes SQL paramétrées permettent d’introduire des variables indépendamment de leur valeur. Il peut donc s’agir de simples nombres ou encore de longues chaînes contenant de multiples caractères spéciaux tels que @,’, `, –, @@, [. %, ] ou toute autre fonction ne se trouvant pas à sa place. Deuxièmement, cela permet aux développeurs flemmards (j’adore ce concept) d’éviter de lourdes méthodes de validation des entrées et ainsi de réduire leurs responsabilités. Finalement : la défense en profondeur reste l’un des principes fondamentaux en matière de sécurité.
La modification de code est mineure en rapport à une requête SQL classique et au vu des audits de code effectués ces derniers mois, la tendance n’est pas à la baisse. Je pense sincèrement que tout développeur ASP classique utilisant encore des requêtes SQL brutes dans ses développements devrait au moins essayer cette technique une fois, ensuite il ne la lâchera plus !
Histoire de faciliter le premier pas, voici un exemple utilisant les requêtes SQL paramétrées en ASP classique :
Dim con, cmd, param
Set con = GetDatabaseConnection()
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandType = adCmdText ‘* pour les requêtes SQL
If(IsFormValid())Then
If(IsUserValid(GetFormString("fuser"), GetFormString("fpassword")))Then
‘* utilisateur est valide mais on ne s’y intéresse pas ici
Else
‘* l’utilisateur n’est pas valide et l’on doit logger sa tentative d’accès
‘* avant de le renvoyer
Dim userIP, userName, userPass, loginErrorSQL
userIP = Request.ServerVariables("REMOTE_ADDR")
userName = GetFormString("fuser")
userPass = GetFormString("fpassword")
‘* notez les points d’interrogation indiquant les insertions de paraètres
loginErrorSQL = ” INSERT INTO logs ” &_
” (log_date, log_ip, log_username, log_message)” &_
” VALUES ” &_
” (?,?,?,?)”
‘* création des paramètres
cmd.CommandText = loginErrorSQL
Set param = cmd.CreateParameter("logDate”, adVarChar, adParamInput, 50, “")
Call cmd.Parameters.Append(param)
Set param = cmd.CreateParameter("logIp”, adVarChar, adParamInput, 50, “")
Call cmd.Parameters.Append(param)
Set param = cmd.CreateParameter("logUsername”, adVarChar, adParamInput, 50, “")
Call cmd.Parameters.Append(param)
Set param = cmd.CreateParameter("logMessage”, adVarChar, adParamInput, 400, “")
Call cmd.Parameters.Append(param)
cmd.Parameters("logDate") = Now()
cmd.Parameters("logIp") = userIP
cmd.Parameters("logUsername") = userName
cmd.Parameters("logMessage") = “echec d’authentification {” & userName & “}/{” & userPass & “}”
Call cmd.Execute()
cmd.CommandText = “” ‘* on vide, juste au cas où
DisplayLoginForm = True
errMsg = “Echec d’authentification”
End If
End If
Vous pouvez maintenant essayer d’insérer des caractères spéciaux dans les différents paramètres des requêtes. Grâce à leur utilisation, le comportement des requêtes restera inchangé. Bien entendu, des contrôles de validation supplémentaires font encore cruellement défaut dans cet exemple, mais ceci fera l’objet d’un autre article.