Tests de sécurité avec Cypress
Testez votre formulaire de contact
Il existe plusieurs stratégies pour imiter les attaques courantes. La stratégie la plus rencontrée avec Cypress est l’utilisation de scénarios de tests préétablis pour les vulnérabilités communes.
Ces scénarios peuvent être basés sur le comportement. Ils vous aident ainsi à identifier les comportements inattendus ou anormaux dans l’application qui pourraient indiquer des failles de sécurité. Ils peuvent également vérifier que les mesures de sécurité implémentées dans l’application fonctionnent correctement dans le cadre de l’utilisation normale.
Testons ensemble le site internet d’exemple.
Pour faire ces tests, vous naviguez sur la page web du formulaire de contact.
Votre environnement doit être monté ; si ce n’est pas déjà le cas, exécutez :
docker-compose up
Allez sur la page du formulaire contact, soit par l’URL http://localhost:3000/frontend/src/contact.html, soit en cliquant dans le menu Contact.
Vous obtenez cette page :
Il y a plusieurs tests à faire :
-
Est-ce que les éléments sont présents ?
-
Est-ce que le formulaire peut être envoyé quand :
-
il est vide ?
-
l’e-mail n’est pas valide ?
-
le message est vide ?
-
il y a une tentative d’injection...
Vérifiez que les éléments du formulaire sont présents
Vous voulez vérifier que les éléments du formulaire sont présents, à savoir les champs : name, email, et message, ainsi que le bouton envoyer (Send).
Comme nous l’avons décrit dans le chapitre Maîtriser la sélection des éléments avec Cypress, la meilleure pratique est d’utiliser les data-cy des éléments. Prenons ensemble le cas du formulaire et spécifiquement l’élément du nom. Dans l’outil de développement, vous avez le détail des éléments.
Pour rappel, avec Chrome, vous pouvez afficher l’outil de développement avec le raccourci clavier [Ctrl][Shift] I. Vous pouvez également le retrouver dans le menu :
Concernant l’élément du nom, vous retrouvez :
Vous pouvez donc utiliser les attributs id, name ou data-cy pour récupérer votre élément, mais choisissez data-cy avec la valeur "contact-name" et vérifiez qu’il existe bien :
cy.get('[data-cy="contact-name"]').should('exist');
Comme nous l’avons vu, si vous n’avez pas de data-cy, vous pouvez vous baser sur l’attribut id ou name, ce qui donnera :
cy.get('input[name="name"]').should('exist');
Vous auriez pu également vérifier...
Utilisez des hooks Cypress
Les hooks Cypress sont similaires aux hooks que l’on retrouve dans d’autres frameworks de test, tels que Mocha ou Jest. Ils vous permettent de définir des fonctions qui seront automatiquement appelées à des moments spécifiques. Les hooks les plus couramment utilisés dans Cypress incluent before, beforeEach, after et afterEach.
Le hook before est utile pour définir les conditions que vous souhaitez exécuter avant une série de tests, et beforeEach avant chaque test ; tandis que after est utile pour nettoyer les conditions après une série de tests, et afterEach après chaque test.
Cypress met en garde sur l’utilisation des hooks after et afterEach pour nettoyer l’état de sortie. Vous ne devez pas, par exemple, nettoyer votre base de données à ce niveau-là. Privilégiez de le faire dans les hooks before et beforeEach.
Dans notre cas, naviguez vers l’URL http://localhost:3000/frontend/src/contact.html avant chaque test.
Le test sera maintenant :
describe('Contact Form Tests', () => {
beforeEach(() => {
cy.visit('/frontend/src/contact.html');
});
it('checks for form elements', () => {
cy.get('[data-cy="contact-name"]').should('exist');...
Vérifiez que le formulaire peut être envoyé si les champs sont remplis correctement
De même, vérifiez que le formulaire s’envoie s’il est correctement rempli. Pour cela, vous allez devoir taper des caractères dans les champs de votre formulaire.
Comme nous l’avons vu au chapitre Maîtrisez la sélection des éléments avec Cypress, voici la commande qui vous permet de taper des caractères :
.type('John Doe');
Le cas d’usage pour vérifier si le formulaire s’envoie si les champs sont remplis correctement est :
-
l’utilisateur se rend sur la page du formulaire de contact ;
-
l’utilisateur tape ’John Doe’ dans le champ nom ;
-
l’utilisateur tape john.doe@example.com dans le champ email ;
-
l’utilisateur tape ’Hello, this is a test message.’ dans le champ message ;
-
l’utilisateur clique sur le bouton envoyer dans le formulaire ;
-
l’utilisateur voit un message ’Thanks for your message !’.
Voici la correction pour vérifier que le formulaire n’est pas vide :
it('submits the form with valid data', () => {
cy.get('[data-cy="contact-name"]').type('John Doe');
cy.get('[data-cy="contact-email"]')
.type('john.doe@example.com'); ...
Vérifiez que le formulaire vide ne peut pas être envoyé
Pour ce test, il faut suivre un schéma que l’utilisateur va suivre : ne pas remplir les champs et cliquer sur le bouton envoyer.
Votre rôle est de vérifier que le formulaire n’est pas envoyé et que les champs textes ont des erreurs et que ces dernières sont compréhensibles par l’utilisateur.
Dans ce site internet, chaque champ texte a une erreur. Dans d’autres sites, le formulaire peut seulement mettre en rouge les champs qui posent problème et mettre une erreur générale sous le formulaire.
Maintenant, vérifions si le formulaire peut être envoyé quand il est vide. Pour cela, vous devez récupérer les autres éléments :
Le bouton pour envoyer le formulaire :
[data-cy="contact-submit-button"]
Les erreurs des champs du formulaire :
-
Nom
[data-cy="contact-name-error"]
-
Email
[data-cy="contact-email-error"]
-
Message
[data-cy="contact-message-error"]
Le cas d’usage pour vérifier si le formulaire vide peut être envoyé est :
-
l’utilisateur se rend sur la page du formulaire de contact ;
-
l’utilisateur clique sur le bouton envoyer dans le formulaire sans remplir les champs ;
-
l’utilisateur voit une erreur sous le champ nom qui contient ’Please enter your...
Vérifiez s’il y a bien une erreur quand un champ est manquant dans un formulaire
Maintenant que vous avez vérifié que le formulaire ne peut pas être envoyé s’il est vide, il faut vérifier s’il y a bien une erreur quand un champ est manquant dans votre formulaire. Pour cela, vous allez devoir réutiliser ce que l’on a vu précédemment.
Le cas d’usage pour le champ nom à simuler est que l’utilisateur :
-
se rend sur la page du formulaire de contact ;
-
tape ’john.doe@example.com’ dans le champ email ;
-
tape ’this is my message’ dans le champ message ;
-
clique sur le bouton envoyer dans le formulaire ;
-
voit une erreur sous le champ nom qui contient ’Please enter your name’ ;
-
ne doit pas voir de message qui lui dit que le formulaire s’est bien envoyé.
La correction est :
it('displays error message for a missing name', () => {
cy.get('[data-cy="contact-email"]')
.type('john.doe@example.com');
cy.get('[data-cy="contact-message"]').type('this is
my message');
cy.get('[data-cy="contact-submit-button"]').click();
cy.get('[data-cy="contact-name-error"]')
.should('be.visible') ...
Vérifiez que les champs ont des tailles minimales ou maximales
Le cas d’usage pour le champ message à simuler est que l’utilisateur :
-
se rend sur la page du formulaire de contact ;
-
tape un nom aléatoire dans le champ nom ;
-
tape une adresse e-mail aléatoire dans le champ email ;
-
tape dix paragraphes dans le champ message ;
-
clique sur le bouton envoyer dans le formulaire ;
-
voit un message ’Thanks for your message’.
Une librairie JavaScript puissante, nommée Faker, vous permet de créer des données fictives telles que des noms d’utilisateurs, e-mails, messages, etc. Vous pouvez retrouver la documentation officielle sur https://fakerjs.dev/
Pour l’installer, tapez la ligne de commande dans le terminal de VSCode :
npm install @faker-js/faker --save-dev
Pour utiliser la librairie, il faut l’importer en haut du fichier :
import { faker } from '@faker-js/faker';
Pour les données des utilisateurs, vous pouvez créer une adresse e-mail fictive et un nom fictif. Faites attention à les stocker si vous devez les réutiliser, dans le cas d’une authentification, par exemple.
const name = faker.person.fullName();
const email = faker.internet.email();
Vous pouvez également afficher le résultat en console :
console.log("name: " + name)
console.log("email: " + email)
Pour créer...
Vérifiez le respect du RGPD
Le RGPD (Règlement général sur la protection des données) est une législation de l’Union européenne qui a été mise en application le 25 mai 2018. Retenez, parmi les points clés du RGPD, qu’une personne a :
-
le droit d’accéder à ses données et d’en obtenir une copie. Le RGPD vise à protéger les données personnelles des citoyens de l’UE, peu importe où ces données sont traitées. Cela comprend des informations telles que le nom, l’adresse, les données de localisation, et les informations en ligne ;
-
le droit de rectifier ses données ;
-
le droit de s’opposer à leur utilisation, sauf si le traitement répond à une obligation légale (par exemple, un administré ne peut s’opposer à figurer dans un fichier d’état civil).
Pour cela, vous devez vérifier :
-
Le consentement :
-
Assurez-vous que le formulaire demande explicitement le consentement de l’utilisateur pour la collecte et le traitement des données.
-
Testez si le formulaire peut être soumis sans accord explicite (par exemple, sans cocher une case de consentement). C’est valable dans quelques cas :
Exécution d’un contrat : si le traitement des données personnelles est nécessaire pour l’exécution d’un contrat avec la personne concernée, le consentement explicite peut ne pas être requis. Par exemple, si une personne remplit un formulaire de commande en ligne pour acheter un produit, le traitement de ses données personnelles (telles que son nom, son adresse de livraison, etc.) peut être nécessaire pour...
Vérifiez que le formulaire ne contient pas de faille XSS
Les tests XSS cherchent à confirmer que votre application ne permet pas l’injection de scripts malveillants, qui pourraient être utilisés pour voler des informations ou corrompre l’expérience utilisateur.
Pour cela :
Essayez d’injecter des scripts JavaScript dans les champs du formulaire, par exemple, en utilisant des entrées telles que "<script>alert(’XSS’);</script>".
Soumettez le formulaire et vérifiez que le script n’est pas exécuté. Cela peut inclure la vérification que les alertes JavaScript ne s’affichent pas et que le code malveillant n’est pas reflété dans la source de la page ou dans les réponses du serveur.
La correction est donc :
it('display error if XSS faille', () => {
cy.get('[data-cy="contact-name"]').type('John Doe');
cy.get('[data-cy="contact-email"]')
.type('john.doe@example.com');
cy.get('[data-cy="contact-message"]')
.type("<script>alert('XSS');</script>");
cy.get('[data-cy="contact-submit-button"]').click();
cy.get('[data-cy="contact-message-error"]')...
Vérifiez que le formulaire ne contient pas de faille d’injection SQL
Le but des tests d’injection SQL est de s’assurer que votre application web n’est pas vulnérable à l’injection de code SQL malveillant à travers les champs de saisie.
Soumettez des chaînes de caractères qui sont typiquement utilisées dans les attaques par injection SQL, telles que "OR 1=1" ou "DROP TABLE users;", dans chaque champ de votre formulaire.
Si un champ de saisie utilisateur, par exemple notre champ commentaire, n’est pas correctement échappé et est directement inclus dans une requête SQL, cette injection pourrait transformer une requête comme ’SELECT * FROM comments OR 1=1’.
La condition ’OR 1=1’ est toujours vraie, donc cette requête retournerait tous les commentaires. Cet impact n’est pas grand mais imaginez-le sur la table utilisateur, l’attaquant pourrait contourner l’authentification !
Pour l’injection SQL ’DROP TABLE users’, elle est beaucoup plus destructrice. Elle peut supprimer complètement la table ’users’ de la base de données.
Vérifiez que le système répond correctement, par exemple, en renvoyant un message d’erreur générique ou en ne permettant pas la modification de la base de données.
Assurez-vous qu’aucune...
Simulez une attaque DDoS sur votre formulaire
Pour simuler une attaque DDoS (Distributed Denial of Service) à petite échelle sur un formulaire, vous pouvez écrire un script qui envoie de multiples requêtes ou soumissions de formulaire en peu de temps. Cette approche peut aider à évaluer comment votre application gère un grand nombre de requêtes simultanées sur un point d’entrée spécifique, comme un formulaire de connexion ou d’inscription.
Pour cela, vous pouvez exécuter le test de base dans une boucle pour générer de multiples soumissions en peu de temps. Cypress fonctionne dans un environnement à thread unique donc, pour simuler simultanément, vous pourriez jouer sur la rapidité des soumissions plutôt que sur la simultanéité réelle.
it('submits the contact form multiple times quickly', () => {
for (let i = 0; i < 50; i++) { // Répète 50 fois,
ajustez selon le besoin
cy.visit('/frontend/src/contact.html');
cy.get('[data-cy="contact-name"]')
.type(`TestUser${i}`);
cy.get('[data-cy="contact-email"]')...