• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 22/07/2022

Protégez votre code contre l’injection

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans ce chapitre, nous allons voir la première vulnérabilité mais également la plus fréquente, l’injection. Nous verrons quels sont les types d’injection et comment s’en prémunir.

Découvrez l'injection

Cette vulnérabilité permet à un attaquant d’injecter des données non maîtrisées qui seront exécutées par l’application et qui permettent d’effectuer des actions qui ne sont normalement pas autorisées.

Ces injections peuvent par exemple être des requêtes SQL pour manipuler la base de données, du code JavaScript ou HTML.

À quel endroit un attaquant effectue une injection ?

Dans une application web, il existe des champs ou des formulaires. Ce sont des composants des applications permettant la saisie de l’utilisateur. Ces champs sont généralement la cible d’injections. Ils se présentent sous la forme d'un formulaire HTML ou d'un champ texte. Ce que vous avez tapé est ensuite traité. Si vous tapez un nom d'utilisateur et un mot de passe, ils seront alors envoyés à la base de données pour pouvoir vous authentifier.

Dans le cas d’une attaque par injection SQL, au lieu de mettre un nom d'utilisateur et un mot de passe sur une page de connexion, un utilisateur malveillant entrera des données directement interprétées par le moteur SQL, ce qui lui permettra de modifier le comportement de votre application.

Prenons un exemple de requête SQL :

SELECT * FROM accounts WHERE username='$username' AND password='$password'
  • SELECT  est un mot clé permettant de sélectionner un élément de la base de données.

  • Le caractère  *  indique que tous les éléments doivent être sélectionnés.

  • FROM  permet d’indiquer la table à utiliser. Dans notre cas, le nom de la table est ‘accounts’.

  • WHERE  spécifie ce que vous voulez sélectionner.

  • username='$username' AND password='$password'  sont les paramètres spécifiques recherchés par cette requête.

Cette requête peut être formalisée par : “Dans la liste des comptes, sélectionne le nom d'utilisateur et le mot de passe qui sont associés au données spécifiées.”

Par exemple, disons que quelqu'un a créé un compte avec le nom d'utilisateur : ‘John’, et le mot de passe : ‘ThisIsMySUperS3cr3tPass’. La requête SQL sera la suivante :

SELECT * FROM accounts WHERE username='John' AND password='ThisIsMySUperS3cr3tPass'

Si l’utilisateur John et son mot de passe sont présents dans la base de données, l’utilisateur sera authentifié.

Cette requête classique peut être contournée par le biais d’une injection SQL. L’exemple suivant nous montre un cas d’exploitation classique.

$username = 1' or '1' = '1
$password = 1or1=1

C'est ce qu'on appelle une instruction conditionnelle ! Elle nécessite que les requêtes respectent des conditions pour s’exécuter.

Dans ce champ,  “$username = 1” et “$password = 1”  sont comparés à l'instruction  '1=1'. Ici, peu importent le username et le password entrés : l’instruction sera toujours valide.

Si nous reprenons notre requête précédente, elle sera interprétée de la manière suivante :

SELECT * FROM accounts WHERE username=1' or ‘1’=’1' AND password=1' or ‘1’=’1''

Un utilisateur malveillant sera ainsi en mesure de s’authentifier avec n’importe quel compte de la base de données, en l'occurrence, ici, le premier compte de la table Account sera utilisé.

Sécurisez une application contre l’injection SQL

Pour garantir une protection contre l’injection SQL, il est possible d’utiliser un pare-feu d'application web ou WAF, pour Web Application Firewall en anglais. Ce pare-feu se place entre l'utilisateur et l’application web et permet de vérifier et d'intercepter les données envoyées. Toutefois il est également possible de sécuriser l’application directement dans le code.

Validez les entrées

La validation des entrées est une excellente pratique en tant que développeur web. Elle limite ce que l'utilisateur peut mettre dans la zone de texte. Avez-vous déjà été frustré lors de la création d'un compte parce qu'il n'était pas possible de créer un mot de passe sans chiffres ou lettres majuscules ?

C'est parce que la validation des entrées a été implémentée : l'entrée est analysée après avoir appuyé sur Entrée. Cela n'empêchera pas l'injection, mais c'est une mesure que vous pouvez mettre en place pour limiter des attaques de base. En effet, les caractères spéciaux spécifiques à certains langages ne pourront pas être utilisés.

Quels types de caractères peut-on limiter lors de la saisie utilisateur ?

Si vous avez dit le signe égal et l'apostrophe, vous êtes sur la bonne voie ! En effet, ces caractères sont interprétés par le moteur de base de données, ce qui veut dire que si un attaquant peut les rentrer dans un champ, ils pourront potentiellement altérer le fonctionnement ; c’est le principe d’une injection SQL. ;)

Paramétrez vos variables !

Vous pouvez écrire vos requêtes SQL en paramétrant les variables. C'est ce qu'on appelle une requête préparée. Examinons l'exemple précédent.

SELECT * FROM accounts WHERE username='$username' AND password='$password'

Pour l'instant, la requête connecte la variable $username directement à la base de données, la rendant vulnérable à l'injection. Avec une requête préparée, le code ressemblerait à ceci :

SELECT * FROM accounts WHERE username='@username' AND password='@password'

Les variables Nom d'utilisateur et Mot de passe sont paramétrées, elles seront donc désormais passées dans une méthode pour exécuter la requête au lieu de se connecter directement à la base de données.

$username = setUser(username)
$password = setPassword(password)

Il existe de nombreuses façons de sécuriser les requêtes SQL, mais comme la requête ne se connecte pas directement à la base de données, il s'agit de l'une des meilleures pratiques pour sécuriser vos données contre l'injection SQL.

Les langages Java, .NET, ColdFusion, PHP et Ruby ont également des fonctions intégrées pour paramétrer vos variables.

Découvrez la différence entre requêtes SQL stockées ou dynamiques

Lorsque vous codez un champ d’entrée utilisateur sur votre application web, vous devez écrire une procédure SQL pour que la base de données sache quelles données extraire. Il y a deux façons de le faire :  stocké et dynamique.  Une procédure stockée est un ensemble d'instructions SQL précompilées, stockées dans une base de données et exécutées sur demande par le système de gestion de base de données qui manipule la base de données. Une procédure dynamique est une technique de programmation qui vous permet de construire des instructions SQL de manière dynamique lors de l'exécution. Les requêtes ne seront pas stockées mais dynamiquement créées. 

Pour sécuriser les requêtes SQL dynamiques, vous pouvez utiliser la fonction  sp_executesql  dans votre procédure SQL dynamique.

Voyons un exemple d’implémentation avec les variables paramétrées ci-dessous :

CREATE PROCEDURE sp_owaspLogin
@bind_username varchar(10)
@bind_password varchar(10)
AS
BEGIN
DECLARE @myquery varchar(100)
SET @myquery = NSELECT login FROM accounts WHERE username = @username AND password = @password
DECLARE @bind_user nvarchar(10) = N’@username’;
DECLARE @bind_pass nvarchar(10) = N’@password’;
EXEC sp_executesql @myquery, @bind_user, @username = @bind_username;

La requête SQL dynamique ci-dessus lie la variable ainsi que la fonction  sp_executesql  pour sécuriser le script.

Utilisez un Object Relational Mapper (ORM)

De nombreux langages disposent d'outils ORM (Object Relational Mapper) qui peuvent obfusquer votre requête, c’est-à-dire masquer son fonctionnement. Les modules ORM tels quepget knexpeuvent être utilisés avec des frameworks JavaScript.

Regardons la requête SQL suivante :

SELECT * FROM accounts WHERE username='@username' AND password='@password'

Tout d'abord, notez que  @username et @password  sont paramétrés !

Voici un exemple de la façon dont une requête correcte sera exécutée dans votre application web à l'aide de knex Node.js.

Dans le code ci-dessous, knex obfusque larequête. Cela signifie qu'il masque ce à quoi ressemble vraiment la requête SQL, ce qui permet d’ajouter une couche de sécurité supplémentaire.

knex('accounts').where('username',john ).orWhere({password: ThisIsMySUperS3c3tPass , user: 'knex'})

Sécurisez vos applications avec l’API OWASP 

L'organisation OWASP dispose d'une API appelée the OWASP Enterprise Security API (ESAPI). Elle peut être utilisée pour sécuriser vos applications web.

En résumé

  • Les injections peuvent inclure (mais sans s'y limiter) des commandes SQL, JavaScript, HTML ou OS.

  • Elles permettent de manipuler les entrées pour effectuer des actions et accéder à des données normalement non autorisées. 

  • Vous pouvez prévenir les attaques par injection en sécurisant votre code avec la validation des entrées, les variables paramétrées, les ORM et les procédures SQL stockées.

  • Les procédures SQL dynamiques peuvent être dangereuses, donc assurez-vous d'utiliser la fonction executesql() dans la base de données pour les sécuriser.

Nous venons de voir comment se prémunir contre les injections ; dans le prochain chapitre, nous verrons comment sécuriser les mécanismes d’authentification dans votre application web.

Exemple de certificat de réussite
Exemple de certificat de réussite