# Enjeux et risques
La sécurité des applications développées est cruciale. Un défaut de sécurité peut permettre des accès aux données (en lecture, mais également en écriture et suppression) ou des opérations non autorisées, des usurpations d’identité (agir au nom d’un autre utilisateur, rendant toute trace d’audit caduque), et jusqu’à l’injection de code malveillant (exécuté sur les serveurs ou chez les utilisateurs) ou l’indisponibilité du service.
La qualité des développements a un impact direct sur la sécurité, avec un risque accru de bugs et des difficultés à en identifier la cause voire à les corriger (et parfois un dilemme : soit on augmente encore la dette technique, soit on doit faire des modifications importantes qui risquent alors d’amener des régressions).
# Points d’attention et problématiques traitées
Un certain nombre de points sensibles sont identifiés comme étant au cœur de la sécurité et la qualité des développements.
La Direction Technique d’Atol CD effectue une veille active sur les pratiques reconnues en termes de sécurité et qualité des développements afin de fournir des recommandations aux équipes.
Les sources d’informations utilisées sont variées et intègrent aussi bien des canaux conventionnels comme les ressources de l’OWASP (comme le Top 10 ou les Cheat sheet series) que des réseaux sociaux avec le suivi de personnalités reconnues dans le domaine de la qualité et/ou sécurité logicielle (par exemple Troy Hunt).
Les règles de bonnes pratiques et de recommandations sont régulièrement mises à jour en même temps que l’état de l’art évolue.
Lors de la réalisation des projets à Atol CD, chacun de ces points est intégré dans la démarche projet.
Pour cela, il est nécessaire d’avoir une vision d’ensemble claire de ces sujets pour les prendre en compte autant dans les choix techniques mais également dans la charge de travail (et donc les impacts en termes de coût et de planning).
# Authentification, gestion des secrets
Une vulnérabilité au niveau de l’authentification peut permettre d’accéder à des données confidentielles, et/ou agir à la place d’un utilisateur. Toute traçabilité des actions indiquera l’utilisateur victime de l’attaque.
Si l’application gère des secrets (par exemple, mots de passe des utilisateurs, ou secrets pour communiquer avec d’autres systèmes), une vulnérabilité au niveau de cette gestion peut permettre, si ces secrets sont récupérés (accès à une sauvegarde par exemple, voire à des logs si les logs sont mal gérés et fuitent les secrets), le credential stuffing dans d’autres services peut permettre d’accéder à des données du même utilisateur (s’il a utilisé le même mot de passe).
# Autorisations
Une mauvaise gestion des autorisations peut permettre à un utilisateur authentifié d’accéder à des données confidentielles ou effectuer des actions sensibles normalement restreintes à d’autres utilisateurs.
Dans le pire des cas, ces données et actions seront même accessibles sans authentification, protégées uniquement par une URL absconse (sécurité par l’obscurité, ça ne marche pas).
# CSRF (Cross-Site Request Forgery)
Un attaquant pourra exfiltrer des données et/ou agir à la place de l’utilisateur authentifié à distance depuis un autre site (éventuellement en profitant d’une vulnérabilité XSS dans un autre site, ou en arrivant à diriger la victime vers un site malveillant)
Une vulnérabilité CSRF permet également des attaques sur des applications intranet depuis Internet, le navigateur de la victime, ayant accès aux deux réseaux, faisant la passerelle. La victime peut également être le serveur lui-même (on parle alors de SSRF –Server-Side Request Forgery–), qui aura accès à des ressources du réseau interne ou pourra participer à des opérations DDoS.
# XSS (Cross-Site Scripting)
Le cross-site scripting permet l’injection de HTML (et donc de CSS et/ou JavaScript) dans une page de l’application. Cette injection peut alors modifier l’affichage, mais également faire des requêtes vers le serveur (Same-Site donc, contournant alors les protections CSRF) avec les privilèges de l’utilisateur victime.
Il y a deux types de XSS : persistant ou non-persistant. Le XSS non-persistant utilise une URL, un cookie, ou un envoi de formulaire comme vecteur et a une action immédiate sur l’utilisateur victime. Le XSS persistant utilise l’application elle-même, et ses fonctionnalités de stockage, pour potentiellement impacter tous les utilisateurs (ex: enregistrer une valeur malveillante dans un libellé/titre d’une donnée, qui sera par la suite affichée par n’importe quel utilisateur ayant accès à cette donnée). Le XSS persistant permet donc l’élévation de privilèges de la part d’un utilisateur malveillant (ou dont le compte a été hacké).
# Injection SQL
L’injection SQL permet de modifier le comportement des requêtes SQL en envoyant des valeurs spécifiques à l’application (dans un entête HTTP, un champ de formulaire, l’URL, un cookie). Une injection SQL permet ainsi de contourner les règles d’autorisation et accéder à des données confidentielles, à les modifier ou les supprimer, voire à supprimer la totalité des données.
# Gestion des dépendances
Les dépendances externes doivent être mises à jour, particulièrement lorsqu’une vulnérabilité y a été détectée (ce qui nécessite de faire une veille). Plus on fera les mises à jour régulièrement, moins le risque de régression et la charge de travail sera grande.
Il faut également s’assurer que les dépendances externes (notamment celles utilisées lors du build du livrable, et donc en production ; mais également dans tout le cycle de développement) sont bien celles que l’on s’attend à utiliser, et n’ont pas été corrompues à la source de téléchargement ou pendant le transport. Cette corruption peut aller d’une simple erreur de téléchargement rendant l’application inutilisable jusqu’à une injection de code malveillant, en passant par un bug / une régression de comportement. Ces derniers types de corruption peuvent survenir dans des nouvelles versions de la dépendance qui se retrouvent utilisées sans même une mise à jour explicite de la part de l’équipe de développement, si les versions (y compris des dépendances transitives) ne sont pas verrouillées avec un mécanisme ad-hoc.
Enfin, au-delà de l’aspect sécurité, la licence des dépendances utilisées est importante également (plus ou moins selon les cas, mais rarement négligeable), et requiert au préalable l’identification précise de toutes les dépendances utilisées.
# Gestion des erreurs et des logs
Une erreur non gérée ou mal gérée peut laisser apparaître des informations sensibles concernant l’implémentation de l’application, ou des données sensibles voire confidentielles. Ces données sensibles peuvent également apparaître dans les logs serveur, potentiellement en violation du RGPD si ces logs venaient à être envoyés à des tiers (pour sauvegarde ou dans des outils d’analyse).
Les logs d’erreur (on ne parle pas de bugs ou de cas non-nominaux ici) sur les actions de sécurité (ex: erreur à l’authentification, tentative d’accès à une donnée non-autorisée) permettent à l’inverse de surveiller les taux d’erreur et détecter les attaques, et doivent donc contenir suffisamment d’informations, mais pas plus que nécessaire.
Configuration secure by default
La configuration par défaut de l’application doit être la plus restrictive possible, et ainsi obliger la configuration explicite pour lever ces restrictions. Une configuration par défaut pas assez restrictive pose le risque qu’elle soit laissée telle quelle en production, avec une application certes fonctionnelle pour les cas nominaux mais trop peu protégée notamment pour des cas plus à la marge et qui ne seront pas forcément identifiés durant les phases de recette ou d’utilisation.
# Qualité du code
Un code de qualité, maîtrisé de bout en bout par l’équipe de développement, permet une meilleure lecture, analyse et maintenance, et évite ainsi toute une classe de défauts (bugs) qui auraient sinon pu passer inaperçus. Et tout comportement non-attendu (bug) peut potentiellement être source de vulnérabilité, même s’ils n’apparaissent que dans des situations rares (par exemple, des problèmes dans la gestion des fuseaux horaires ou des paramètres régionaux, ou des caractères étendus Unicode).
# Connexions sécurisées
Une connexion non sécurisée peut permettre à un attaquant de lire tous les échanges, voire de les modifier, par exemple en y injectant des données malveillantes. La sécurisation des connexions (avec TLS la plupart du temps) permet d’en garantir l’authenticité (que le client parle bien au bon serveur), la confidentialité (par chiffrement cryptographique) et l’intégrité (aucune altération des données). Les paramètres cryptographiques sont importants et peuvent permettre la confidentialité persistante (forward secrecy) qui garantit la confidentialité des échanges passés même en cas de fuite de la clé privée du serveur.
# Méthodes et outillages Atol CD
# Construction des livrables sur Jenkins
Les livrables sont construits dans un environnement isolé pour éviter au maximum les effets de bords qu’une construction sur un poste de développement causerait à coup sûr (modification locale absente du dépôt de code, malware éventuel présent sur le poste, etc.)
# Relecture de code
Toute modification de la base de code passe par une phase de relecture par au moins un autre développeur de l’équipe.
La relecture permet de détecter d’éventuels bugs avant qu’ils n’intègrent le dépôt de code, de discuter des choix d’architecture, de partager la connaissance du code à l’ensemble de l’équipe, et vise à améliorer la qualité du code et sa maîtrise par l’équipe de développement.
# Outillage d’analyse statique de code
Des outils d’analyse statique de code (intégrés au compilateur ou externes) sont utilisés à différents stades du développement (sur le poste du développeur, sur le serveur d’intégration pour chaque relecture de code, à chaque modification validée et/ou toute les nuits) pour obtenir des diagnostics sur la qualité du code : bugs potentiels, règles de nommage, formatage du code.
# Suivi des dépendances via Dependency Track
L’arbre des dépendances d’un projet est analysé à chaque modification pour en extraire les informations sur les licences, et comparé à des bases de données de vulnérabilités connues pour détecter d’éventuels problèmes de sécurité.
# Serveur d’intégration Jenkins
Chaque modification de la base de code, en phase de relecture et après validation, est automatiquement construite, et les tests automatisés lancés, dans un environnement isolé afin de détecter au plus tôt tout problème. Une modification en relecture doit passer cette vérification avant de pouvoir être validée dans le dépôt de code.
# Serveur de développement
Des serveurs de développement, de démonstration voire de recette sont utilisés pour mettre en pratique les procédures de déploiement, et permettre une pré-recette et des feedbacks rapides sur les développements.
Laisser un commentaire