L’OWASP, pour Open Web Application Security Project, est un organisme mondial non lucratif qui travaille sur l’amélioration de la sécurité des logiciels. A ce titre elle présente de nombreuse bonne pratique à mettre en place dans les applications web.
1. Des normes
En amont des bonnes pratiques techniques de l’OWASP, il faut identifier les organismes qui régissent la sécurité et mettent en place les normes :
- Depuis 2018, le Règlement Général sur la Protection des Données (le fameux RGPD) concerne tous les citoyens de l’Union européenne et donc, par extensions, tous les sites qui propose du contenue à ces citoyens : il indique la manière dont les données personnelles peuvent être stockées et utilisées ainsi que des directive sur les traitements autorisés.
- La Payment Card Industry Data Security Standard (PCI DSS) concerne elle les entreprise qui utilise des données bancaires et définit ainsi comment elle peuvent être stockées, comment elles doivent etre transmis et traitées.
- Le Code de la Santé Publique restreint aussi la manière dont les données de santé pour être utilisées ; le Règlement européen sur la protection des données personnelles et la Loi Informatique et Liberté définisse aussi des restriction sur l’usage des données utilisateurs. Ces informations sont notamment présentées par la CNIL (Comission National Informatique et Liberté)
Bien que les bonnes pratiques de l’OWASP ne remplace pas la mise en place des solutions de sécurité lié à chacune des normes propres à des situations précise (données de santé, bancaire etc.) elles en inclue une bonne partie et constitue un bon prerquis pour toute application sécurisé.
Voici donc 7 règles de sécurité propre à l’OWASP.
1. L’injection SQL
Le risque d’injection (cf. de code) fait souvent référence au problème d’injection SQL : via un formulaire, il est par exemple facile d’indiquer en mot de passe « Patate OR 1=1 ». Resultat, une requete SQL classique pourrait faire « SELECT * FROM Users WHERE name= »admin » AND password=’patate’ OR 1=1″. Et le pirate serait connecté en tant qu’administrateur car 1 est bien égal à 1.
C’est un type de risque à part entière car, à partir de cette injection SQL, il est d’agir sur la Base de donnée (modifier, supprimer…) mais aussi possible d’insérer en base de données différents code (html, css, javascript) qui pourrait aller s’afficher sur les page générées aux utilisateurs.
Etape 1 : Contraintes HTML
Les champs de saisies représentant un risque pour une application web, il est important de correctement les balisés. Les navigateurs actuels incorporant un contrôle supplémentaire leur formatage correct a d’autant plus raison d’être.
<input type="password" maxlength="30" name="actual_name" placeholder="Mot de passe de 30 caractère max" required autocomplete="off" /> <!-- le type password contraindra le navigateur à des contrôles et l'attribut "required" imposera le fait de remplir obligatoirement le champs. le maxlength permettra de limiter le nombre de caractère. Autocomplete="off" empêchera que des valeurs précédentes puissent être réutilisées -->
Etape 2 : Contrôler les données
Tout d’abord, avant tout envoie de donnée en BD peut être envisagé de valider les champs selon des contrôles personnalisés. On peut effet vouloir s’assurer que la donnée transmise correspond bien à ce qui est attendu, que son format ([email protected]) est cohérent avec ce qui est attendu, qu’aucun caractère indésirable n’est présent ou qu’aucun mot dangereux n’apparaît. Exemple :
function CheckEmailField(){
//Instruction de vérification du type de données
//Instruction de Nettoyage de la donnée (exemples :)
echo filter_var($dirtyAddress, FILTER_SANITIZE_EMAIL);
$newsletter = filter_var($_POST['newsletterCheckbox'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
//Instruction de vérification de format (via Regexs)
}
D’autre part, il peut être envisager de « 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. Encore mieux, on peut supprimer les balises. Ou encore, il existe un moyen plus fin de filtrer la valeur d’une variable selon des options.
function RemoveInsecureTags(){
$withoutTags = strip_tags("<script>Du script !</script>");
//$withoutTags = "Du script !"
$var = htmlspecialchars("<hahaha>Du script !</hahaha>");
//var = "$lt;hahaha>Du script !$lt;/hahaha>";
}
Enfin, pour les fichiers qui transitent via un formulaire, il est impératif de vérifier leur contenu, leur poids, leur extension (etc) avant de les accepter.
//en PHP
$path_parts = pathinfo($_FILES['screenshot']['name']);
echo $path_parts['dirname'], "\n"; //emplacement
echo $path_parts['basename'], "\n";
echo $path_parts['extension'], "\n"; //permet de vérifier l'extension du fichier.
echo $path_parts['filename'], "\n";
//Etc.
Etape 3 : Objet de requêtage SQL.
Ensuite, préférer l’utilisation d’objet destiné à la manipulation de données SQL : les ORM (Object Relational Mapper). Ces objets permette de décomposer la requête afin d’en binder des données (nos entrées HTML traitées) directement et uniquement à des champs SQL.
//PHP avec PDO on peut lier des variable aux champs correspondant.
$request = SELECT * FROM accounts WHERE username=:username AND password=:password
//PDO s'initialise en amont, avec la chaine de connexion à la BD
$pdo->prepare($sqlQuery);
//Possibilité A : utiliser un tableau associatif
$datas = $db->execute([ //... les deux valeurs de ce tableau.
'username' => $username,
'password' => $password,
]);
//Possibilité B : Utiliser la methode bindValue qui permet d'être encore plus précis :
$pdo->bindValue(':username', $username, PDO::PARAM_STRING);
$pdo->bindValue(':password', $password, PDO::PARAM_STRING);
$db->execute();
Les ORMs selon les langages (Linq en C#, knex en javascript etc) permette aussi de construire une requête en l’obfusquant : en ne donnant jamais la possibilité de prendre en paramètre une chaine SQL construite manuellement mais en la construisant via des méthodes.
knex('accounts').where('username',john ).orWhere({password: ThisIsMySUperS3c3tPass , user: 'knex'})
//JS : On comprend ici qu'on SELECT * FROM accounts WHERE username='John' OR (password='ThisIsMySUperS3c3tPass' AND user: 'knex').
//Mais par contre il n'y aucun string de requête, donc pas moyen de modifier à la volée sa structure.
Etape 3B : Utiliser des procédures stockées
Les procédures SQL stockées en SGBD ont l’avantage de dissocier clairement la gestion des requêtes SQL d’un côté et la gestion des entrées utilisateur de l’autre. De plus, elle permet de répartir clairement les compétences et sont donc très adaptés pour les projets volumineux. Elles sont d’ailleurs équipé de la méthode sp_executesql qui permet de sécurisé l’execution du script SQL.
CREATE Procedue sp_owaspUserLogin //(...) EXEC sp_executesql(@myQuery);
Etape 4 : API Owasp !
L’OWASP fournit une API, la ESAPI (OWASP Enterprise Security API) qui permet de répondre à ces différent besoin : page web officielle.
Etape 5 : WAF WAF
Enfin, de manière davantage « structurel », il est aussi possible d’utiliser un pare-feu d’application web ou WAF (Web Application Firewall).
2. Le piratage de Session
Afin d’accéder à une session d’utilisateur, c’est à dire à son espace une fois connecté sur un site avec ses identifiants, les pirates tenteront de pirater sa session. Les deux technique les plus connus pour ça est le Credential Stuffing (obtenir d’une manière ou d’une autre les identifiants de l’user et les utiliser pour se connecter) ou l’attaque par force brute (tenter, selon des probabilités, des combinaisons user/mot de passe). Des solutions existes :
Etape « 0 » : Configuration par défaut
Bien que moins répandue en milieux professionnel, il est tout de même bon de rappeler l’intérêt de supprimer les comptes par défaut (« root », « admin » etc.) ou tout du moins de modifier leur mot de passe initial. Ces comptes présentent clairement un risque de sécurité.
De plus, il faut s’assurer que les comptes existants n’aient bien QUE les droits dont ils ont réellement besoin (principe du moindre privilège)
Etape 1 : Sensibiliser les utilisateurs.
A l’heure actuelle (16/05/2022), le Guide des Bonnes pratique informatique éditée par le gouvernement conseille :
Choisissez des mots de passe composés si possible de 12 caractères de type différent
GUIDE DES BONNES PRATIQUES DE L’INFORMATIQUE
(majuscules, minuscules, chiffres, caractères spéciaux) n’ayant aucun lien avec vous
(nom, date de naissance…) et ne figurant pas dans le dictionnaire
De plus, il est une bonne pratique de renouveler régulièrement son mot de passe.
Etape 2 : Limiter le nombre d’essai
L’attaque de force brute est basée sur la capacité extrêmement forte qu’a un ordinateur à faire des opérations rapidement. Là où faire 3 essais devient pénible pour nous, un programme conçu pour un piratage… ne se lassera pas. De plus il pourra générer l’ouverture de plusieurs page d’identification et faire des très nombreux essais à la seconde.
Ainsi il est nécessaire de restreindre le nombre d’essai autorisé ; une pratique répandue est de le limiter à 3 ou encore 5.
Etape 3 : Protéger vos cookies
Les cookies, petit fichier stockées dans le navigateur de l’utilisateur, sert à stocker des élément l’identifiant notamment afin de personnalisé son expérience : son prénom (« Bonjour Olivier »), son historique de navigation (« Vous avez liké cet article »), son temps de session (« Vous allez être déconnecté par mesure de sécurité ») etc. Toutefois, ces cookies étant accessible via un identifiant, si un pirate A après que le site 1 stocke ses information dans un cookie appelé « PersonnalUserInformation » rien ne l’empêche d’y accéder. Il faut donc toujours :
- Ne pas stocker d’information en clair dans le cookies, mais plutôt les chiffrés.
- Définir une date d’expiration utile afin de ne pas conserver des cookies trop longtemps
- Dans le cas d’HTTPs, penser à chiffre les transmissions des cookie.
Etape 4 : Cuisiner les identifiants utilisateurs.
Outre les bonnes pratiques des cookies, le chiffrement des données sensibles utilisateurs doit être une règle lorsqu’il s’agit de la stocker. Le chiffrement consiste à déterminer une valeur inintelligible à partir d’une chaine intelligible selon une logique (« MotdePasse2022* » peut devenir « NpuefQbttf3133/ » selon la logique « remplacement une lettre par la suivante », et on peut donc déduire la valeur initiale en utilisant la logique inverse).
Le hashage lui permet de déterminer une valeur inintelligible selon une logique tellement éloigné que le processus de déchiffrement est impossible ; simplement, le résultat sera toujours le même (« MotdePasse2022* » pourrait devenir « qshdcn’iuf++UIU-52*41/234 », systématiquement via ce processus sans qu’il soit possible de passé du hash vers la valeur initiale). Lorsqu’on récupérera le mot de passe saisi par l’utilisateur, on le hashera et le comparera à ce qui a été stocké en base de donnée.
Toutefois actuellement des Ranbow Table existe (table arc-en-ciel) contenant des listes de mot de passes probables et leur équivalent en hash fréquent (MD5, SHA-1). A l’heure actuelle il donc est conseillé d’utiliser un hashage combiné à un « sel ». Alors qu’une méthode de hashage renverra par exemple toujours « 52/ùù » pour « Bonjour », elle pourra renvoyé « 963)°*! » pour « Bonjour » avec le sel « Olivier » et « 3dfUl. » pour « Bonjour » avec le sel « Marine ».
Cela permet donc d’obtenir une valeur inintelligible mais qui dépend d’un d’une valeur supplémentaire, d’éviter par exemple que deux utilisateur ai exactement le même mot de passe stockée en BD et surtout compliquer le travail d’un programme pirate qui chercherait à déterminer comme sont transformé les mots de passe (la combinaison n’étant pas une simple concaténation).
//Java
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(salt);
byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8))) ;
//PHP : Depuis PHP7 il n'est plus possible d'utiliser un sel personnalisé pour éviter les sels trop peu sécurisés
$passwordHash = password_hash($passwordInput, PASSWORD_BCRYPT); //utilise un "sel" par défaut sécurisé
//De plus, en PHP, la bibliothèque SessionManager disposerait d'une méthode preventHijacking pensée pour limiter l'accès aux données de sessions au seul et unique hôte à laquelle elle a été confié.
//https://github.com/khalidsheet/session-manager
SHA-1 (Secure Hash Algorithm) et MD5 (message-digest algorithm) sont des fonctions de hachage cryptographique.(…) Contrairement aux algorithmes SHA et MD5, Argon5, PBKDF2, Bcrypt et Scrypt sont plus axés sur la sécurité que sur l’efficacité (…) : le cassage de ces algorythme exige plus de ressources.
https://openclassrooms.com/fr/courses/6179306-securisez-vos-applications-web-avec-lowasp/6520207-protegez-les-donnees-stockees-sur-une-application
(…) Argon5 est un des algorithmes de hachage les plus puissants et fortement recommandés par l’OWASP
Etape 5 : Multi-Factor Authentification
Une autre pratique de sécurité est de multiplié les facteur d’authentification : identifiant/mot de passe, lien dans un mail, code sur un téléphone etc. Cela renforce efficacement la sécurité.
Outils
Voici une liste des framework réputé pour leur prise en charge de la sécurité que fournit OpenClassroom :
– ASP.NET Core IdentityFramework peut être intégré dans votre application web pour personnaliser vos besoins d’authentification. L’ajout d’ASP.NET Core IdentityServer vous permet d’utiliser les techniques de développement sécurisé pour l’authentification par jeton.
Openclassroom, Sécurisez vos applications web avec l’OWASP
– Ruby a des fonctions (gems) comme omniauth qui peuvent être implémentées pour l’authentification.
– Java a javax.security.auth, et l’API Java Authentication and Authorization Service (JAAS), qui peuvent configurer votre authentification de la bonne façon !
– PHP a PHPSec peuvent être utilisés pour gérer la sécurité et les sessions.
3. L’exposition des données sensibles
Le protocole HTTP est un protocole non sécurisé qui fait transité ses données en clair. Autrement dit, une personne connecté au même réseau qu’un utilisateur, avec le logiciel adéquate (sniffer réseau), sera en mesure de voir tout ce qui est échangé entre lui (son ip) et le site en HTTP qu’il utilise. C’est ce qu’on appelle l’attaque de l’homme du milieu (ou attaque MITM, Man in the Middle).
La seule manière d’éviter cela est de sécurisé le canal de communication entre l’utilisateur et le site ; et pour cela ils faut donc changer de protocole en allant vers le HTTPS. Ce protocole utilisait SSL (Secure Socket Layer) aujourd’hui obsolète et utilise maintenant TLS (Transport Layer Security) pour acheminer les informations de manière chiffrées.
Etape 1 : Obtenir un certificat TLS (nouveau SSL)
La première étape consiste dans le fait d’obtenir un certificat valide pour le site visé. Ce certificat va entrer dans la configuration du site et permettra qu’il soit reconnu comme un site de confiance lié à une identité propre (le certificat). L’étape, longue, peut être suivi sur un tutoriel comme celui-ci : https://github.com/zaproxy/zap-core-help/wiki/HelpUiDialogsOptionsDynsslcert.
Une pratique répandu aujourd’hui est de passer par certbot.
Etape 2 : Spécifier le protocole HTTPS
Maintenant que le certificat est obtenu, il faut indiquer, dans le langage souhaité, que le site utilise le protocole https. Selon la technologie (.NET, Ruby, PHP…) les étapes fluctuent mais nécessite toujours de spécifié au niveau de la configuration que le site à activer les pages sécurisés HTTPS.
Etape 2Bis : Rediriger vers le HTTPS
Le requêtage vers le site en http restera normalement possible mais donc soumit à des vulnérabilités. Il faut donc penser à empêcher l’accès en redirigeant notamment vers le site https, générant ainsi une réponse 301 ou 302.
//Dans le virtualhost qui correspond au HTTP :
Redirect permanent / https://www.example.com/
Il est aussi recommandé d’utiliser HTTP Strict Transport Security (HSTS) pour que les navigateurs soient informés d’utiliser seulement HTTPS au moment de requêter le serveur.
Etape 3 : Utiliser correctement les CORS
Les CORS, Cross-Origin Resource Sharing, sont un ensemble de mécanismes permettant d’encadrer, côté serveur, les sites (sources, domaines ou « origines ») autorisés à requêter le serveur. Les contrôler permet d’accentuer la sécurité d’un site.
//Entête à renvoyé par le serveur
Access-Control-Allow-Origin: https://domaine.ext/
//Implémentation PHP
header("Access-Control-Allow-Origin: https://domaine.ext/");
De plus amples informations disponible ici : https://developer.mozilla.org/fr/docs/Web/HTTP/CORS
Etape 4 : Masquer les données
Au niveau de la base de données, il est possible d’utiliser des mots clé ou méthode pour masquer les données : l’idée est de renvoyé une autre valeur que celle réellement présente en BD. La données initiale peut donc être utilisé pour le requetage à la base, mais renvoyé masquée (remplacée par une valeur par defaut).
//SQL (Transact-SQL) Birthdate DATE MASKED WITH (FUNCTION = 'default()') NOT NULL,
Une autre méthode peut être de masquer en redirigeant des requetes de selection vers une autre base de données « miroir » ne contenant que des fausses données : ainsi, les données retournée ne sont pas les bonnes et les rendent donc inexploitable.
4. L’exploitation du contrôle d’accès
Etape 1 : Créer des rôles/droits cohérents
Il est important de modifier les comptes admins existant pour ajuster les droits qu’ont chaque utilisateur, quitte à créer des groupes plus fins, afin de respecter le principe de moindre privilège (un utilisateur ne doit pouvoir faire que ce qu’il a besoin de faire).
En bases de données il s’agira dans la plupart des cas de créer des rôles adéquates.
Etape 2 : Ne pas être trop explicite
Les IDOR, ou Insecure direct object references (Référence direct d’objet non sécurisé), sont une faille de sécurité évident pour un site. Derrière l’acronyme se cache notamment le fait d’apeller sa page « Connexion_administrateur.php » ou « GetUser.php?idUser=536 ». Ou encore de laisser des messages d’erreurs comme « the t_admins_users table hasn’t a ‘secure_password’ field ».
En effet, un pirate un peu vicieux pourra vite s’en servir pour deviner d’autre page, tenter de changer facilement des paramètre ou déduire des champs de BD.
Le plus sûr est donc :
- de nommer les pages avec un système qui évite de donner des informations aux pirates : admin.php pourrait devenir admin_conn_restrict.php tandis que l’user aurait Authent_for_user.php, évitant la possibilité de deviner l’un à partir de l’autre. Ou mieux : utiliser des urls personnalisés empêchant l’accès aux fichiers. Une attaque par octet nul (./) peut en effet extraire une partie du code d’une page connue.
- Ne pas utiliser de nom par défaut « EditUser.php », « UpdateArticle.php » ou encore les noms de fichiers par défaut issu d’un design partern (MVC, MVVM), notamment pour éviter l’attaque de l’octet nul
- S’assurer que la vérification d’authentification est présente sur toutes les pages qui en ont besoin et pas uniquement sur la page « d’entrée » (exemple la page d’accueil administrateur)
- Ne pas afficher des code d’erreur trop verbeux qui afficherait des informations sur la structure de la BDD en personnalisant les codes d’erreur et les exceptions
5. Insertion de code (XSS)
L’insertion de code directement dans la page web, ou mal nommé Cross (X) Site Scripting (Codage Inter-Sites), permet à terme son exécution (généralement javascript) dans le navigateur. Ce qui sous-entends accès au cookie, redirection de l’utilisateur, affichage de message indésirable etc.
De son propre aveu, un des pionner de cette technologie l’a incorrectement nommé car cette faille ne concerne pas nécessairement une action d’un site à un autre.
« Le problème n’est pas simplement le « scripting », et il n’y a pas forcément quelque chose entre plusieurs sites. Alors pourquoi ce nom ? En fait, le nom a été donné quand le problème était moins bien compris, et c’est resté. Croyez-moi, nous avions des choses plus importantes à faire que de réfléchir à un meilleur nom. »
Mark Slemko, « Cross Site Scripting Info »
Etape 1 : Contraintes les champs HTML
Comme vu pour l’injection SQL, la base est de limiter le plus possible le champs d’action des champs HTML.
Etape 2 : Contrôler les données
Encore une fois, il est nécessaire donc de contrôler les données entrées dans les champs avant de les traiter.
Etape 3 : restreindre l’accès aux cookies
Le javascript représentant une faille, il peut être une bonne pratique d’empêcher purement l’accès aux cookies via javascript. Et cela est justement possible via leur option « HttpOnly ».
//PHP, Signature de la méthode setcookie()
setcookie(string $name, string $value = "", int $expires_or_options = 0, string $path = "", string $domain = "", bool $secure = false, bool $httponly = false): bool
// ou via la signature de méthode apparu dés PHP7
setcookie(
'NAME',
'Value',
[
'expires' => time() + 30, //Expire dans 30 secondes
'secure' => true,
'httponly' => true,
]
);
Etape 4 : Renforcer l’authentification
« Insérer du HTML en XSS, qu’est l’intérêt ? » Peut-on penser. Imaginons alors qu’une personne A est connecté au site de sa banque mabanque.com. Elle est donc capable de faire des transferts, consulter ses e-cartes, accéder à l’historique de ses achats… Imaginons maintenant que dans un site non sécurisé sitenonsecurise.com un pirate injecte un lien du type mabanque.com/transfert.php?ToIban=FR450MT45515452&Amount=1500. Alors l’utilisateur en cliquant dessus, serait capable d’effectuer un transfert à un IBAN donnée un montant désigné étant donné qu’il est déjà connecté au site de sa banque. C’est la faille CSRF, pour Cross-Site Request Forgery, Requête Contrefaites Inter-Sites (car là l’utilisateur passerait de sitenonsecurise.com à mabanque.com).
Openclassroom conseil pour lutter contre cela quelques bonnes pratiques :
- « Exiger la réauthentification pour toutes les demandes des utilisateurs. »
Cette pratique peut-être particulièrement bienvenue pour toute opération très sensible, et on l’a trouve actuellement sur certain site bancaire (qui vont jusqu’à demander une MFA) - « Utiliser un jeton unique pour chaque demande. »
Les Jetons CSRF sont des signature (ex : Hkvq23b4n8sgh1d5h684s6j4gd3hsd) unique à un utilisateur pour une demande donnée. Il peut être obtenu dés la demande d’une opération et être vérifié à la finalisation de la demande : ainsi, si un lien CSRF amène sur la finalisation directement, la vérification du jeton échouera car introuvable. - « Utiliser des jetons anti-falsification qui valident le jeton côté client par rapport au jeton côté serveur web.«
- « Effectuer des recherches sur les bibliothèques CSRF basées sur la sécurité«
De nombreuse librairie, framework et autre incorpore déjà des mécanisme de défenses ; il peut être utile de les utiliser.
5. Encercler les iFrame
Les iFrames représentent un risque de sécurité, étant une injection de code créé par l’utilisateur.
Etape 1 : Décorer
Un attribut a vue le jour pour restreindre ses activités au cadre de l’iFrame : l’attribut sandbox. Il peut simplement décorer la balise ou être renseigné comme n’importe quel attribut pour plus de précision.
http://getusercontent.cgi?id=12193
<!-- Restreint le fonctionnement au seul limite de l'iFrame -->
http://maps.example.com/embedded.html
<!-- Authorise les scripts, les formulaire ET les communication avec le serveur d'origine -->
Etape 2 : Restreindre la source
Côté serveur, on pourra définir un entête qui restreindra la source des iFrames.
//Avec nginx, on pourra ajouter la ligne suivante à la configuration HTTP, serveur ou à la configuration de l'emplacement (location) :
add_header X-Frame-Options SAMEORIGIN always;
Etape 3 : restreindre la destination
Aussi, il est possible de n’autoriser que certains sites à utiliser notre site web comme un iFrame. Attention, X-Frame-Options peut surcharger les comportement suivant car selon le choix il définit le paramètre dans les deux sens (vers un site externe ou depuis un autre site).
//Empêche par exemple que le site soit utilise comme un iFrame quelque soit l'endroit
add_header Content-Security-Policy "frame-ancestors 'none';";
//Autorise que depuis le site courant
add_header Content-Security-Policy "frame-ancestors 'self';";
//Ou autorisé depuis plusieurs domaines spécifique
add_header Content-Security-Policy "frame-ancestors 'yoursite.com' 'example.com';";
6. Les failles XXE
Le format de structure donnée XML possède une faille : ses entités externes. En effet les entités, qui peuvent être simplifiés en variable, ont deux mode d’initialisation : à partir d’une donnée déclarée en dur (interne) et à partir d’une ressource (externe).
L’attaque XXE (donc pour XML External Entities) profite d’une faille dans certains analyseur XML pour aller déclarer une entitée externe &externe1 qui ira récupérer le contenu d’un fichier type c:/desktop/passwords.txt (contenant, mettons, « MonMotDePasse123* ». Ensuite, sur ce même site exploitant le xml comme format de donnée, il ira insérer dans un formulaire la valeur &externe1 en tant qu’User pour que la page suivante lui affiche « L’utilisateur MonMotDePasse123* n’existe pas » et obtiendra ainsi le mot de passe.
Etape 1/1 : Désactiver les entités externe
Contre cela rien de bien compliqué : la solution est de désactiver les entité externes des XML pour éviter tous risque. L’implémentation dépend du langage et de l’analyseur xml mais l’idée et de changer le flag correspondant.
//JAVA
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
7. Serialisation/Deserialisation
Une fois vue toutes les méthodes d’injections possible, il faut envisager un risquer plus important : car autant l’environnement navigateur est risqué (redirection, affichage modifié, vol d’informations) autant rien ne peut être écrit ou exécuté. Mais si le code injecté comporté un risque côté serveur ? C’est possible en cas de sérialisation d’objet non sécurisé.
Exemple : un script est chargé de sérialisé les données d’un objet avant de les envoyé côté serveur. Puis, le serveur, confiant, désérialise l’objet et l’utilise en l’initialisant. Et bien dans cas, si le code injecté auparavnt a eu pour but de modifier l’objet à serialisé (en faisant exécuté via son constructeur des opérations dangereuses) alors après désérialisation l’objet pourra exécuter des instructions côté serveur, avec ces droits propre à l’environnement serveur.
Etape 1 : Sécuriser les données d’entrées
Une fois de plus, et car il ne faut jamais faire confiance aux données utilisateurs, il est necessaire de vérifier les données entrées avant toutes sérialisation pour s’assurer qu’elles sont bien conforme à ce qui est attendu.
Etape 2 : Sécuriser la désérialisation
Ensuite il faut utiliser des bibliothèques ou tout autres outils sécurisant l’étape de désérialisation. Côté Java, la bibliothèque SerialKiller a été conçu pour cela : https://github.com/ikkisoft/SerialKiller.
8. Path disclosure
Les chemins relatifs peuvent êtres exploité comme des failles des vulnérabilité (PRSSI, Path Relative StyleSheet Import). Dans le cas où un pirate parvient à réecrire le fichier css à importer, cela ouvre la voie à des problèmes de sécurité.
Voir Evil CSS Injection, Relative Path Overwrite Attack ou Research paper: Large-Scale Analysis of Style Injection by Relative Path Overwrite.
Il est donc recommandé d’éviter les liens relatifs pour l’import de CSS, et donc d’utiliser des liens absolu. De plus, voici quelques manières d’éviter les PRSSI :
It is recommended to remove relative URLs and use absolute URLs in CSS imports.
The following alternatives can be applied to avoid PRSSI vulnerabilities.
- Definir un DOCTYPE qui n’autorise pas le Quirks mode (Explications)
- Définir une entête de réponse « X-Frame-Options: deny »
- Definir une entête de réponse « X-Content-Type-Options: nosniff »
- Mettre en place une balise HTML qui spécifie l’URL de base pour toutes les urls relaltives (?)
Conclusion
La sécurité dans les applications web (et en général) représente un problème car elle n’a, pendant longtemps, pas été inclu dans le cycle de vie d’une application. Est estimé à 80% la part des applications en productions vulnérables aux attaques courantes.
Il en résulte de nombreuses applications web qui doivent être tester (via des méthodes dont le Fuzzing, le test d’intrusion, le Threat Modelling ou via un Audit de teste par une entité tierce) afin d’apporter des correctifs. D’ailleurs, à des fins d’évaluation de la sécurité et de son suivi, il est important de mettre en place des système de monitoring et des journaux d’historisation des différentes actions sur l’applications, dont les accès aux données sensibles.
Aujourd’hui le cycle de vie intégré de la sécurité (SDLC) est de plus en plus utilisé par les organisations qui ont d’important projets logiciels. D’autre part le cycle de vie de développement logiciel sécurisé (SSDLC) propose aussi une alternative viable.
Veille
Car il faut toujours se tenir à jour sur ces malins de petits hackers, voici quelques liens :
- La base de données Common Vulnerabilities and Exposures créée par le MITRE récence les vulnérabilité connues
- Le site officiel de l’OWASP https://owasp.org/
- Le site du RGPD et de la cnil : https://gdpr.eu/ et https://www.cnil.fr/
- https://www.root-me.org/ pour tester vos compétences de hacker !
- https://tryhackme.com/ en anglais, qui enseigne la cybersecurité de manière fun
Sources
- https://openclassrooms.com/fr/courses/6179306-securisez-vos-applications-web-avec-lowasp
- https://www.ssi.gouv.fr/uploads/2017/01/guide_cpme_bonnes_pratiques.pdf
- https://developer.mozilla.org/fr/docs/Web/HTTP/CORS
- https://fr.wikipedia.org/wiki/Cross-site_scripting