Le web est sujet à différentes failles de sécurités. Cela se passe aussi bien du côté du serveur qui hébérge le site (côté back) que depuis l’accés au site via le navigateur (côté front). Petit tour d’horizon des bonnes pratique de conception web en terme de sécurité.
La sécurité
Il y a différents aspects auquel une application (web) doit répondre pour réponde à des enjeux de sécurité :
- L’authentification : il doit être nécessaire qu’une entitée s’authentifie pour accéder à différentes partie de l’application (par mot de passe, par certificat, double…)
- Le contrôle d’accès : concrètement un rôle doit être lié à l’entité authentifié pour lui ajouter des droits correspondants justement à ce qu’il peut faire.
- La confidentialité des données : le chiffrement des données, comme les mots de passe, assurent un que les données stockées restent confidentielles
- La non-répudiation : concerne les moyens mises en oeuvre pour s’assurer que l’emetteur et recepteur d’un message ont bien été identifié.
- Protection contre l’analyse de traffic : globalement, deux protocoles (SSL et TLS) permettent, via le HTTPS, de sécuriser les communication.
Prévention
La création d’un fichier de log permet de répondre à des besoins d’analyse globale d’une base de donnée. De plus, cela peut offrir des statistiques. Aussi cela permet potentiellement de reproduire des opérations en echecs.
Voici les informations qui serait utile dans un tel journal :
L’horodatage de l’événement ;
OpenClassRoom
L’estimation de la sévérité de l’événement ;
L’identité du compte concerné ;
L’adresse IP associée avec la requête ;
Le résultat (échec ou réussite) ;
Une courte description.
A des fins de sécurité il peut être en effet important d’avoir un historique des erreurs d’authentification et des évènements liés aux accès à l’application.
Gare au XSS
En 2019, il était estimé que « 80 % des failles des applications web sont dues à une faille XSS.« .
Le XSS pour Cross-site Scripting est une technique qui consiste à à « injecter du code HTML contenant du JavaScript dans [les] pages, pour le faire exécuter [aux] visiteurs. ».
Injection Javascript
Typiquement en passant par l’url ou par des champs de formulaire, un utilisateur pourra y insérer du code javascript malicieux comme des balises de script exécutant du code javascript. Exemple :
<script>alert('test')</script>
En effet, Openclassroom rappel à juste titre que via javascript il est possible :
– Modifier ou ajouter des clefs à la base de registre de la machine victime ;
OpenClassroom
– Afficher une fenêtre demandant à l’utilisateur de rentrer son login et son mot de passe puis de valider, après quoi le résultat sera envoyé par courriel à l’attaquant
– Récupérer les cookies présents sur la machine victime ;
– Exécuter des commandes systèmes ;
– Construire un lien vers un site malveillant et diriger l’internaute vers celui-ci.
Imaginons maintenant que le script javascript arrive à être stockée en BD dans un champs via une injection SQL et op : le script est renvoyé systématiquement dans la construction de certaine page à beaucoup d’utilisateur… c’est le cas de la faille permanente.
Pour éviter cela, il faut « détruire » ce qui pourrait être interpréter comme des balises javascript. Une méthode simple et de convertir les caractères <> par $lt; et > qui demande explicitement d’afficher ces caractères.
Contraindre l’accès au cookies
Aussi, l’accès au cookie doit être sécurisé pour éviter que le javascript puisse y accéder (cela permettrait notamment qu’un script javascript d’un autre site récupère les cookies existant pour exploiter les informations stockées). Il faut donc activer leur flag « HttpOnly ».
Injections HTML/CSS
Bien que ces injections puissent paraître sans réel danger il faut les prendre en compte pour éviter la possibilité d’insérer des messages malveillant par exemple (HTML). De plus, concernant le CSS, du fait de son développement récemment, Openclassroom envisages plusieurs risque :
– On peut exécuter du Javascript grâce aux fonctions
expression()de IE ;
– On peut utiliser les sélecteurs CSS pour lire des parties du code HTML de l’application. Ce cas peut s’avérer dangereux si l’utilisateur malveillant peut lire des jetons CSRF (…) ;
– On peut capturer toutes les données passées en paramètres d’une requête HTTPGETen créant une feuille CSS importées d’une URL du domaine de l’attaquant.
De la même manière que pour le javascript, il faut échapper les caractères qui pourrait être perçu comme du html ou du css. Sinon, dans certains cas, on peut autoriser pour des champs qu’un certain nombre de valeurs (ou en interdire certaines).
Les Iframes
Les widgets tel que googlemaps et autres twits utilisent parfois des iframe, qui font donc récupérer du contenu à l’extérieur : cela représente un risque. Un attribut a été mit en place pour restreindre les actions possible DANS l’iFrame, l’attribut « sandbox ».
Enfin de manière général, pour chaque champs HTML, il est judicieux de suivre les recommandation de l’OWASP (Open Web Application Security Project) sur les tests à réaliser pour chaque type de champs : https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html
Contrôler les sources javascript
Enfin, pour s’assurer qu’aucune source javascript non connues ne soient chargées, il est possible dans le protocole http de spécifié une entête pour autoriser la source des script : les Content-Security-Policy.
Il sera par exemple possible de restreindre l’exécution de script à ceux provenant du site en lui même (valeur ‘self’) et d’un site en particulier.
Plus d’information sur les entêtes sécurisées : https://w3c.github.io/webappsec-csp/
Halte aux injections SQL…
Su le web on peut via un langage serveur, envoyer nos requete de selection de données au SGBD. Afin qu’elle soient personnalisé, on peut être tenté d’utiliser la concaténation de variable pour obtenir des données. Example : « SELECT * FROM $table ». Mais dans le cas où $table est elle même une requette SQL (ex: « t_table2; DROP TABLE t_table1 »), on peut imaginer une faille de sécurité. Pour contrecarrer ça, deux solutions :
Typer et contraindre au mieux les champs HTML
Un champs HTML sensé indiqué un prénom ne devra par exemple pas permettre d’écrire une requête contenant 100 caractères. Une bonne pratique pour les champs est donc d’indiquer leur type quand c’est possible, de contraindre leur longueur à ce qu’ils sont sensé présenté, utiliser des regex pour vérifier qu’ils respectent un format.
<input type="email" maxlength="100" placeholder="[email protected]" />
Préférer un objet propre au requêtage
Ensuite, lors du requetage SQL, il est plus sûr d’utiliser des objets dédiés qui permettent de s’assurer que la valeur fournit ne fait que représenté la valeur d’un champs sql, et uniquement ça. Souvent ces objets permettre de « préparer des requetes » puis de les « executer ».
Ces objets construisant les requêtes utilisent des moteurs d’ORM (Object-Relational Mapping) : PDO, Doctrine etc.
…et aux injections côté Serveur
De la même manière qu’on peut pousser un serveur APACHE (donc linux) à exécuter des commandes. Si une valeur est attendue en via la methode GET, dans l’url donc, on peut indiquer une valeur et des commandes linux (ex: « Olivier; rm * -rf », qui formate le contenu du répertoire courant). L’astuce consiste à utiliser, lors de la réception des données, une methode qui échappe tous les caractères qui pourrait être utilisées comme une commande.
//PHP $securedValue = escapeshellcmd($value);
Injection de fichiers dangereux
De la même manière, lors de l’envois de fichier, il faut s’assurer clairement que les fichiers fournis par l’utilisateur correspondent bien au type attendu : image pour une photo de profil, document pour un cv etc. Un fichier « .php » pourrait par exemple provoquer d’important risque de sécurité s’il parvient à être exécuté par la suite.
L’attaque arc-en-ciel
Les mots de passes sont des plus en plus rapide à deviner pour les ordinateurs modernes. De plus, il existe par exemple le site RainbowCrack qui recense les mots de passes les plus rencontrés sous format MD5. Cela permet aux hacker de facilement lancer des attaque en tentant des authentification avec ces mots de passé ; il s’agit d’une attaque arc-en-ciel.
Il ne faut jamais stocker les mots de passes en clair, mais les chiffrer. On peut par exemple les chiffrer via MD5, mais si l’utilisateur utilise le même mot de passe pour plusieurs application, une fois le contenu chiffré trouvé, le pirate pourrait utiliser n’importe service de l’utilisateur. De plus, le MD5 est facile decryptable.
Le mieux est de passer par un chiffrage complexe à plusieurs itération comme BCrypt (ou PBKDF2 ou argon2) prenant en compte un « sel » : une chaine de caractère propre à l’utilisateur sur un site donné, permettant de chiffrer le mot de passe et le seul en même, rendant le chiffrage unique à l’application.
<?php
//Enregistrement du mot de passe
$options=array(
'salt'=>random_bytes(22,MCRYPT_DEV_URANDOM), //ici on renseigne le "sel"
'cost'=>12, //détermine le nombre d'iteration pour le chiffrage
);
$password_hash=password_hash($password_string,PASSWORD_BCRYPT,$options);
//(...) on stock le hash en BD
//Puis :
$verify = password_verify($plaintext_password, $password_hash);
?>
Vol de données
» D’après l’ANSSI, le principe de moindre privilège stipule qu’une tâche ne doit bénéficier que des privilèges strictement nécessaires à l’exécution du code menant à bien ses fonctionnalités. En d’autres termes, une tâche ne devrait avoir la possibilité de mener à bien que les actions dont l’utilité fonctionnelle est avérée. »
OpenClassRoom
Il est nécessaire sur une application web de cloisonner au mieux les fonctionnalité et les utilisateurs pour ne limite leurs droits qu’à ce qu’ils ont besoin de faire (la référence est la documentation de l’ANSSI)
En bonne pratique il faut donc :
- Lister les privilège nécessaire à chaque fonctionnalité de l’app et la développer dans un environnement adéquate (où les droit d’accès aux dossiers et ressources sont cohérent) via des chmode définit en FTP.
- Interdire les accès par défaut aux ressources protégées
- Mettre en place une limite au nombre de requête réalisable par un utilisateur sur le système
- Créer des journaux (ou logs) qui référencent toutes les demandes d’accès
Failles liées aux sessions (dont CSRF)
Les sessions sont susceptible, dans le cas improbable d’un identifiant qui transite via l’URL, d’être subtilisé via une attaque par fixation de session. De plus, la session étant géré par cookie, côté serveur ou côté BD, il faut identifier le stockage.
Aussi, une personne connectée avec des droits admin pourrrait, en cliquant sur un lien avec en url des params l’amenant à supprimer un utilisateur : c’est la faille CSRF (Cross-Site Request Forgeries).
Pour éviter les risques, il est conseiller de :
- Générer un identifiant de session soit même via un algorithme cryptographique
- Ne stocker en Cookie que l’identifiant de session
- Utilisez des cookies « HTTP Only » pour éviter que l’information soit récupérable via javascript
- Dans le cas du https, il faut renseigner dans le cookie « secure = true »
- Fixer une durée de vie d’une maximale à une session (timeout)
- Créer un jeton unique par utilisateur associé à une page : en cas de vol de l’id de session, la requête au serveur ne sera de toute façon pas accepté car
<?php
$token = md5(bin2hex(openssl_random_pseudo_bytes(6))); //génère un token CSRF
?>
Protection des données
Il est facile d’accéder à certaine données ou de les modifier lorsqu’on doit passer des paramètre en URL. Typiquement, des liens email peuvent proposer des chose comme monsite.com/ValidUserEmail?user=5686. Ici, en remplaçant l’id, on peut effectuer une opération non autorisé : c’est une faille de référence directe d’objet.
Pour l’éviter, une solution est la création d’un lien qui comporte en plus une valeur impossible à deviner en procédant au chiffrement des données
//PHP : example de genration du lien
$hash = md5('5686');
//$hash = 07bb5fdef1ee99d35eaccce14f8b5540;
$lien = monsite.com/ValidUserEmail?user=5686?hash=07bb5fdef1ee99d35eaccce14f8b5540;
//PHP : exemple de vérification du lien
$id = $_GET['user'];
if(md5-$_GET['user'])==$_GET['hash'])
//On valide l'adresse mail !
Ainsi, en changeant uniquement le « user », le lien ne marchera pas : la vérification échouera.
Toutefois, ce système est à l’heure actuel trop facile à craqué : on comprendre bien que le hash vaut un chiffrement de l’user ! Un pirate malin pourrait tenter de trouver quel chiffrement est utilisé.
Donc, il faut complexifier le chiffrage avec d’autres données :
$mdp_user="MotDePasse*1234";
$generateLinkDate="2022-06-13";
$hash = md5('5686'.$mdp_user.$generateLinkDate);
//$hash = 342e6cf48be7f5d743d8c553c075bf4a;
Ici, le hash à vérifier correspondra à deux informations en BD (le mot de passe et la date de génération du lien) ; même en connaissant le chiffrage, le pirate ne pourra pas deviner facilement les informations.
Canaux de diffusion
La securité des données et en partie permise par le chiffrage des données échangées (avec le client, les serveurs partenaires). Une bonne pratique est donc de sécurisé les moyens de communications en chiffrant les données qui y transitent via la mise en place du protocole TLS.
Cela est permit par le passage en https d’un site web, via la mise en place d’un certificat.
Tests et Revues
Parce que la sécurité doit être une préocupation à chaque étape du cycle de vie d’une application, et surtout car on ne sait jamais vraiment quelle nouvelles methodes auront trouvé les hackeurs pour contourner les bonnes pratiques, il est important de procéder à des revues et à des tests :
- Les Revues de conceptions sont des documents qui évaluent la sécurité au niveau de larchitecture de l’application (et permet donc de détecter des faille de haut niveau).
- Les Revues d’implémentation sont des document issus d’outils d’analyse de code pour y trouver des vulnérabilité. On peut par exemple cité l’outil « Qualis ».
- Les Tests de sécurité, via l’exemple des tests de pénétration, permettent de discerner des failles.
Bonnes pratiques
Pour terminer, voici des bonnes pratiques à appliquer :
- Utiliser, quand cela est possible, des objets securisées (tel que SecureString en .NET)
- Vider/Supprimer des variables ou toutes autres données lorsqu’elles ne sont plus nécessaires
- Chiffrer les données importantes de l’application pour qu’elle n’apparaissent pas en clair tel que la clé d’accès à la BD (voir https://fr.acervolima.com/comment-chiffrer-et-dechiffrer-une-string-php/)
- Chiffrer les données sensibles en base de données (mot de passe, carte bancaire, information personnelles)
- Quand c’est possible, utiliser des variables fortement typée !
- Deconnecter le lien avec la base de donnée quand il n’est plus nécessaire.
- Eviter les messages d’erreur SQL pouvant donner des indication sur la structure de la base de données
- Ne pas indiquer de données sensible dans les messages d’erreur (exemple : le mot de passe ‘Supermotdepasse@2022’ n’a pas été reconnu dans la Base de donnée »
Sources
- https://openclassrooms.com/fr/courses/1761931-securisez-vos-applications/
- https://www.commentcamarche.net/contents/50-xss-cross-site-scripting
- https://fr.wikipedia.org/wiki/Injection_SQL
- https://blog.sucuri.net/2021/10/how-to-set-up-a-content-security-policy-csp-in-3-steps.html
- https://sql.sh/fonctions/md5