Sécuriser les applications Python Flask
Gourav Singh Bais
21 mai 2024
0 minutes de lectureFlask est un framework web Python puissant, léger et polyvalent, conçu pour permettre aux développeurs de créer rapidement des applications web avec un minimum de code standard. Ce microframework autonome ne nécessite aucune bibliothèque ni aucun outil supplémentaire et ne dispose pas de couche d’abstraction de base de données.
Flask comprend des fonctionnalités telles que le routage, le rendu de modèles et la gestion des requêtes, et respecte la norme Web Server Gateway Interface (WSGI), réputée pour sa simplicité et sa flexibilité.
Malheureusement, comme tout autre framework web, Flask est exposé à des vulnérabilités s’il n’est pas correctement sécurisé. Les risques de sécurité les plus courants pour Flask comprennent les scripts intersites (XSS), la falsification de requêtes intersites (CSRF) et l’injection SQL.
La Snyk Vulnerability Database répertorie de nombreuses vulnérabilités de sécurité découvertes dans la bibliothèque Python Flask :

Dans cet article, découvrez les bonnes pratiques pour sécuriser les applications Python développées avec le framework web Flask. Vous commencerez par examiner quelques exemples de configurations non sécurisées, puis apprendrez à atténuer et à corriger les problèmes.
Qu’est-ce que la norme Web Server Gateway Interface (WSGI) ?
WSGI fournit un moyen standardisé pour permettre aux serveurs Web de communiquer avec les applications Web écrites en Python. Cette couche intermédiaire permet aux serveurs Web de transmettre les requêtes à une application ou à un framework Web, puis de renvoyer les réponses au client.
Pourquoi WSGI est-il important ?
Avant WSGI, les frameworks web Python et les serveurs étaient souvent étroitement liés : un framework web donné ne pouvait fonctionner qu’avec certains serveurs web. WSGI a supprimé cette contrainte, offrant davantage de flexibilité et d’interopérabilité.
En quoi WSGI est-il comparable à des concepts similaires dans d’autres langages ?
WSGI a un rôle similaire à l’API Java Servlet en Java ou à Rack en Ruby. Ces technologies abstraient les détails des requêtes et des réponses HTTP, permettant aux développeurs de se concentrer sur la logique de leurs applications web plutôt que sur la communication sous-jacente avec le serveur.
Configurations non sécurisées des applications Python Flask
Voici quelques-uns des problèmes de configuration non sécurisée les plus courants qui touchent les applications Python Flask. Les développeurs doivent veiller à ne pas reproduire ces erreurs dans leur base de code :
Exposition de la clé secrète
La divulgation accidentelle d’une clé secrète est un problème de sécurité courant : des informations sensibles, comme la clé secrète Flask, les clés d’API et les mots de passe, sont intégrées au code source. L’intégration directe de données confidentielles dans le code source présente un risque de sécurité important, car des acteurs malveillants peuvent exploiter cette vulnérabilité pour accéder sans autorisation à différents services.
Si vous avez codé en dur votre clé secrète et votre clé d’API dans le code source, le résultat ressemblera à ceci :
Conseil : c’est le bon moment pour installer l’extension Snyk dans votre IDE. Vous pourrez ainsi repérer visuellement l’exposition d’une clé secrète, comme le trait bleu ondulé affiché dans mon éditeur :

Pour prévenir l’exposition d’une clé secrète dans ce cas, vous devez la générer de manière sécurisée. Il existe plusieurs méthodes, dont l’une des plus courantes consiste à utiliser le module uuid. Le module uuid sert principalement à générer des identifiants uniques universels (UUID) selon les principes définis dans RFC 4122. Il génère une chaîne hexadécimale aléatoire de 32 octets, utilisable comme clé secrète.
Pour générer une clé sécurisée, importez le module uuid dans votre code et utilisez la fonctionnalité uuid4().hex :
Toutefois, générer la clé secrète ne suffit pas. Vous devez également l’utiliser de manière sécurisée dans votre application Flask. La méthode recommandée consiste à affecter la clé secrète à une environment variable ou à utiliser un fichier de configuration chiffré pour l’y stocker. Si vous choisissez de l’affecter à une environment variable, voici à quoi cela ressemblera :
Les développeurs doivent suivre des conventions de configuration telles que celles recommandées par l’application 12 Factor et utiliser des variables d’environnement pour stocker leurs identifiants. Ils évitent ainsi les fuites de données, les accès non autorisés et les utilisations abusives potentielles.
Mode débogage activé
Le mode débogage est généralement destiné aux environnements de développement. Il fournit des messages d’erreur détaillés ainsi que des informations complètes sur l’état de l’application. Cependant, son activation en production expose des informations sensibles et le fonctionnement interne du système.
Par exemple, dans cette application web Flask, le mode débogage est activé en production :
Ici, le mode débogage est défini sur True. Ainsi, si une erreur se produit en production, des informations sensibles, notamment les noms d’utilisateur et les mots de passe, peuvent être exposées dans la console de débogage.
Dans ce cas, il est très facile d’oublier que vous avez défini le mode débogage sur True et de ne pas le désactiver avant le déploiement de votre application en production. C’est pourquoi il est préférable d’utiliser une plateforme comme Snyk, qui vous aide à détecter et à corriger les vulnérabilités de votre code et de vos applications. Snyk prend en charge un large éventail de langages de programmation, dont Python, Go, PHP, JavaScript et d’autres.
De plus, Snyk s’intègre facilement à différents IDE, notamment Visual Studio Code et PyCharm, ainsi qu’aux pipelines CI, tels que Jenkins, CircleCI et Maven, et aux workflows.
Par exemple, pour utiliser Snyk dans ce scénario de débogage, il vous suffit de rechercher « Snyk » dans Visual Studio Code et de l’installer :

Une fois l’installation terminée, Snyk apparaît dans le panneau de gauche. Cliquez sur le bouton Connect pour vous connecter ou créer un compte Snyk si vous n’en avez pas encore. Une fenêtre de navigateur semblable à celle-ci s’ouvrira alors :

Une fois connecté, retournez dans Visual Studio Code et ouvrez le dossier contenant votre script Flask. Vous devriez maintenant pouvoir repérer les vulnérabilités dans votre code :

Comme vous pouvez le constater, Snyk a détecté que le mode débogage était toujours activé. Pour corriger ce problème, sécurisez votre application Flask en définissant le mode débogage sur False :
En plus de désactiver le mode débogage en production, utilisez également le mécanisme de journalisation pour recueillir les journaux de l’application et repérer d’éventuels problèmes dans le code.
Données sensibles non protégées dans les fichiers de configuration
Stocker des informations critiques (par exemple, des identifiants de base de données, des clés d’API et des clés de chiffrement) dans des fichiers de configuration est une pratique courante dans les applications Flask. Cependant, ces données peuvent être compromises si vous ne protégez pas ces fichiers.
Prenons l’exemple d’un fichier de configuration (généralement config.ini) contenant les identifiants de connexion à la base de données :
Ici, le nom d’utilisateur et le mot de passe sont indiqués en texte brut. Si un attaquant accède à ce fichier, il peut utiliser ces identifiants pour consulter des informations sensibles.
Pour résoudre ce problème, le mieux est d’éviter les fichiers de configuration et d’utiliser des variables d’environnement pour stocker vos identifiants. Comme les variables d’environnement regroupent toutes les informations nécessaires dans un fichier caché, tel que .bash_profile, vous pouvez simplement ajouter ce fichier à gitignore afin d’éviter de le pousser accidentellement vers des plateformes de gestion de versions telles que Git ou Bitbucket, auxquelles les attaquants peuvent facilement accéder.
Si vous devez utiliser des fichiers de configuration dans votre application Flask, veillez à chiffrer les données sensibles :
Ici, un espace réservé ou une valeur chiffrée représente le mot de passe. Dans ce cas, les données sensibles peuvent être consultées à l’exécution à l’aide d’un système externe sécurisé de gestion des clés ou d’une méthode de déchiffrement sûre.
Vulnérabilités des applications Flask
Maintenant que vous en savez un peu plus sur les configurations non sécurisées des applications Python Flask, examinons quelques vulnérabilités courantes de sécurité web qui peuvent également toucher les applications Flask.
Scripts intersites (XSS)
Une vulnérabilité XSS est une faille de sécurité web par laquelle un attaquant tente d’injecter du code JavaScript ou HTML arbitraire dans une page web. Les attaquants peuvent ainsi exécuter des scripts malveillants dans le navigateur d’un utilisateur.
Jinja2, le moteur de templates utilisé par Flask, propose une fonctionnalité d’échappement automatique pour traiter les vulnérabilités XSS. Par défaut, toutes les variables sont automatiquement échappées (c’est-à-dire qu’elles ne contiennent aucun élément HTML, sauf indication contraire). Ainsi, toute entrée utilisateur contenant du code HTML ou JavaScript est échappée de manière sécurisée par Jinja2, ce qui empêche l’exécution de scripts malveillants.
Si l’échappement automatique est défini sur False, l’application Flask est vulnérable aux attaques XSS. Par exemple, voici une application web qui demande une saisie à l’utilisateur pour afficher une page :
La page index.html correspondante, où l’échappement automatique est défini sur false, ressemblerait à ceci :
Si un attaquant injecte un script malveillant via le paramètre input, celui-ci s’exécute lors de l’affichage de la page et peut entraîner des risques de sécurité, tels que le vol de données, la prise de contrôle de comptes et des attaques par hameçonnage.
Pour prévenir les attaques XSS, les développeurs doivent configurer leur site web de manière à échapper correctement le texte et à exclure tout élément HTML. Il suffit de définir l’échappement automatique sur true pour protéger l’application Flask contre les attaques XSS :
Une autre méthode de prévention des attaques XSS consiste à échapper explicitement le balisage. Pour cela, utilisez le filtre |safe sur une page web, comme ceci :
Toutefois, utilisez |safe avec beaucoup de précaution, car ce filtre considère que le contenu marqué comme sûr est exempt de tout script malveillant.
Pour en savoir plus sur les vulnérabilités de type script intersite en Python, consultez une courte leçon de sécurité sur Snyk Learn.
Falsification de requêtes intersites (CSRF)
Une attaque CSRF trompe une victime pour l’amener à soumettre une requête malveillante. Dans une application web, l’attaquant envoie une requête non autorisée à une page au nom de l’utilisateur autorisé. Ce type d’attaque peut se produire sur des plateformes comme Facebook : quelqu’un envoie une image à un groupe et, si des membres cliquent dessus, leur compte est supprimé.
Pour mieux comprendre le CSRF, examinons une simple application qui modifie l’état sans protection CSRF :
Ce code envoie un formulaire pour changer le mot de passe à l’aide d’une requête POST. En l’absence de protection CSRF, un attaquant peut inciter les utilisateurs à modifier leur mot de passe en les redirigeant vers un autre site web contenant du code HTML ou un script spécialement conçu. Un formulaire sans protection CSRF ressemble à ceci :
Pour prévenir les vulnérabilités CSRF, utilisez l’extension Flask-WTF avec le middleware CSRFProtect. Flask-WTF est un plug-in Flask qui intègre la bibliothèque WTForms, laquelle fournit des fonctionnalités pratiques pour créer et gérer facilement des formulaires dans une application web Flask.
Vous pouvez l’installer avec pip comme suit :
Une fois l’installation terminée, vous pouvez mettre à jour votre application Flask avec Flask-WTF pour la protéger contre les attaques CSRF :
Ici, CSRFProtect est initialisé avec l’application Flask et la variable SECRET_KEY est définie. Cette clé sert spécifiquement à créer et à valider les jetons CSRF.
N’oubliez pas de mettre à jour le template (index.html) pour y inclure le jeton CSRF, comme ceci :
La fonction csrf_token() génère un champ de saisie masqué contenant le jeton CSRF. Lors de l’envoi du formulaire, Flask-WTF valide le jeton pour s’assurer que la requête ne résulte pas d’une attaque CSRF.
Injection SQL et sécurité des bases de données
Examinons maintenant quelques problèmes liés à la sécurité des bases de données dans Flask :
Injection SQL
L’injection SQL est un problème grave : un attaquant exécute du code SQL arbitraire sur une base de données en manipulant les paramètres d’une requête SQL. Cette attaque peut entraîner des accès non autorisés, la manipulation de données et la divulgation d’informations sensibles.
Dans les applications Flask, une attaque par injection SQL peut se produire si les entrées ne sont pas correctement assainies avant d’être utilisées dans une requête SQL.
Pour mieux comprendre cette attaque, examinons un exemple de code Flask qui récupère des données dans une base de données :
Cette requête attend le nom d’utilisateur et le mot de passe dans la chaîne de requête. Si un attaquant injecte des valeurs telles que ' OR '1'='1'; -- , la requête devient :
Comme cette requête renvoie toujours True, l’attaquant peut se connecter et accéder sans autorisation aux données.
Il est difficile de repérer le code vulnérable aux injections SQL, mais Snyk peut vous aider. Snyk étant déjà configuré dans Visual Studio Code, il vous suffit d’ouvrir le script pour que Snyk détecte automatiquement le problème d’injection SQL :

Pour atténuer facilement cette attaque par injection SQL, utilisez des requêtes ou des instructions paramétrées. Dans
Flask, vous pouvez également utiliser la méthode execute de l’objet curseur pour lier les paramètres de manière sécurisée. Une requête paramétrée ressemble à ceci :
Dans ce code, des espaces réservés ? sont utilisés. Leurs valeurs réelles sont fournies sous forme de tuple dans la méthode execute, ce qui garantit que les entrées utilisateur sont traitées comme des données et non comme du code SQL exécutable.
Veillez à toujours valider et assainir les entrées utilisateur pour éviter ce type d’attaque. Vous pouvez assainir les entrées à l’aide de techniques comme les caractères d’échappement, les bibliothèques tierces et les expressions régulières.
Pour approfondir le sujet des injections SQL, je vous recommande de lire Le guide de prévention des injections SQL : 8 bonnes pratiques pour les contrer.
Authentification et autorisation
L’authentification et l’autorisation sont des composantes essentielles de la sécurité web. Une faille dans l’authentification ou l’autorisation peut entraîner plusieurs problèmes de sécurité, que nous allons aborder.
Problèmes de sécurité liés à l’authentification
L’un des problèmes de sécurité les plus courants liés à l’authentification est l’attaque par force brute, lors de laquelle un attaquant tente à plusieurs reprises de deviner un nom d’utilisateur et un mot de passe pour accéder à un site web ou à un service. Un autre problème fréquent est la fixation de session, où l’attaquant définit l’ID de session sur une valeur connue, éventuellement au moyen d’une attaque par hameçonnage.
Pour atténuer les attaques par force brute, vous devez mettre en place un mécanisme de verrouillage de session. Dans ce cadre, l’utilisateur est bloqué après un certain nombre de tentatives de connexion infructueuses :
Dans ce code, vous définissez MAX_LOGIN_ATTEMPTS sur 3. Ainsi, si une personne saisit des identifiants incorrects plus de trois fois, son compte est bloqué.
Dans la méthode login(), vous récupérez le username et le password, puis vérifiez si l’utilisateur est bloqué. Si ce n’est pas le cas, vous vérifiez le nombre de tentatives de connexion. Si les identifiants sont corrects, tout va bien. Sinon, le nombre de tentatives augmente de un et le processus se répète jusqu’à ce que l’utilisateur parvienne à se connecter ou soit bloqué.
En plus d’un mécanisme de verrouillage de session, vous devriez également appliquer des règles robustes en matière de mots de passe et envisager d’utiliser l’authentification multifacteur (MFA).
Pour atténuer les problèmes de fixation de session, vous pouvez régénérer les ID de session après la connexion de l’utilisateur ou au bout d’un certain temps (expiration automatique), même si l’utilisateur reste connecté :
Dans ce code, la méthode login() régénère l’ID de session à l’aide de la méthode regenerate() une fois la connexion de l’utilisateur réussie.
Problèmes de sécurité liés à l’autorisation
Lors du développement d’une application web, toutes les fonctionnalités ne sont pas destinées à chaque utilisateur (c.-à-d. un utilisateur donné ne devrait avoir accès qu’à un ensemble limité de fonctionnalités). Si les rôles ne sont pas correctement attribués aux utilisateurs, des accès non autorisés peuvent se produire. C’est pourquoi vous devez mettre en place un contrôle d’accès basé sur les rôles (RBAC).
Il est également possible que des utilisateurs authentifiés accèdent à des ressources non autorisées en manipulant des paramètres ou des URL. Ce problème est souvent appelé référence directe non sécurisée à un objet (IDOR). Pour en savoir plus, je vous recommande vivement de lire cet article sur la détection et la correction des références directes non sécurisées à un objet en Python.
Pour résoudre les problèmes liés au RBAC et aux IDOR, vous devez attribuer des rôles spécifiques aux utilisateurs et appliquer des contrôles d’accès en fonction de ces rôles, comme ceci :
Dans ce code, la méthode admin_dashboard() implémente les fonctionnalités auxquelles les utilisateurs ayant le rôle admin doivent pouvoir accéder. Dans le cas contraire, elle renvoie un avertissement « Unauthorized access ».
Vous devez également gérer le contrôle d’accès afin que les utilisateurs ne puissent accéder qu’aux ressources auxquelles ils sont autorisés :
Vous ne devriez pas stocker les identifiants en texte brut, car des attaquants pourraient facilement y accéder à des fins malveillantes. Pour l’éviter, vous devriez utiliser le hachage et le salage pour stocker les identifiants des utilisateurs.
Le hachage transforme un mot de passe en une chaîne de caractères de longueur fixe, rendant le processus inverse et la récupération du mot de passe d’origine irréalisables sur le plan informatique. Le salage consiste à ajouter une valeur aléatoire unique (le sel) à chaque mot de passe avant le hachage, ce qui contribue à prévenir les attaques par tables arc-en-ciel.
Bibliothèques obsolètes et mises à jour de sécurité
Si vous utilisez des bibliothèques Flask obsolètes, elles peuvent contenir des vulnérabilités exploitables par des attaquants. Les bibliothèques publient régulièrement des mises à jour de sécurité et des correctifs pour résoudre les vulnérabilités. Veillez toujours à utiliser la version la plus récente des packages.
Pour vous assurer d’utiliser les derniers correctifs de sécurité, vous pouvez utiliser des outils comme pip ou conda. Vous pouvez également utiliser des outils comme Snyk pour analyser l’ensemble de votre code, ainsi que vos dépendances et vos configurations d’infrastructure as code (IaC).
Une autre bonne pratique consiste à figer les dépendances dans le fichier requirements.txt. Le projet utilise ainsi des versions spécifiques, ce qui permet aux développeurs de maîtriser les mises à jour et de tester la compatibilité.
Sécuriser les téléversements de fichiers
Si un site Flask permet à n’importe qui de téléverser n’importe quel type de fichier, plusieurs problèmes peuvent survenir. Par exemple, si un attaquant téléverse des fichiers malveillants sur le serveur, une attaque par déni de service (DoS) peut se produire, avec un risque d’écrasement des fichiers existants. Certains fichiers exécutables peuvent également contenir différents types de virus informatiques.
Voici un exemple de code qui permet à n’importe quel utilisateur de téléverser n’importe quel fichier :
Dans ce code, la méthode upload_file() lit le fichier fourni par l’utilisateur, puis le stocke dans le dossier uploads.
La première solution pour éviter les fichiers non sécurisés consiste à définir une liste d’extensions de fichiers autorisées. Vous ne devriez jamais autoriser les fichiers exécutables ou les scripts dans votre application Flask.
Veillez également à stocker les fichiers dans un emplacement sécurisé afin d’éviter tout accès non autorisé :
Ici, plusieurs conditions ont été appliquées pour vérifier l’authenticité des types de fichiers.
Une autre bonne pratique consiste à attribuer des noms aléatoires aux fichiers afin d’éviter leur écrasement et de réduire le risque lié à des conventions de nommage prévisibles :
Gestion des erreurs et divulgation d’informations
La gestion des erreurs est importante dans tout type d’application. En production, il est déconseillé d’utiliser des instructions print et d’activer le mode débogage. Un mécanisme de journalisation inapproprié peut révéler des informations importantes sur votre application.
Par exemple, afficher un message d’erreur détaillé en production peut révéler des informations sensibles sur le fonctionnement interne de l’application et faciliter l’identification de vulnérabilités potentielles par des attaquants :
Cet exemple révèle les informations les plus importantes sur la base de données associée à l’application Flask.
De plus, afficher les traces complètes dans les réponses d’erreur peut révéler la structure du code de l’application et potentiellement exposer des vulnérabilités, comme ceci :
Pour atténuer la divulgation d’informations lors de la gestion des erreurs, vous pouvez créer des pages d’erreur personnalisées pour les codes d’erreur génériques (p. ex. 404 Not Found et 500 Internal Server Error), sans révéler de détails sensibles. Pour cela, vous pouvez utiliser le décorateur errorhandler afin de définir des gestionnaires d’erreurs personnalisés :
Vous devriez également mettre en place une journalisation adéquate des exceptions et des erreurs. Les messages de journal doivent être suffisamment détaillés pour faciliter le débogage, sans révéler d’informations sensibles :
En appliquant ces bonnes pratiques, vous pouvez vous assurer que votre application Flask est robuste et sécurisée.
Conclusion
Flask est un framework web populaire pour les applications web de petite et moyenne envergure. Cependant, comme tout autre outil ou framework de développement web, Flask peut présenter des problèmes s’il n’est pas utilisé correctement. Il est important non seulement de connaître ces problèmes, mais aussi de savoir les atténuer pour empêcher les acteurs malveillants d’en tirer parti.
Nous vous invitons à suivre ce dépôt de code sur GitHub pour découvrir des exemples complets et fonctionnels de certains des sujets liés à la sécurité des applications Flask abordés dans cet article.
Snyk vous aide à détecter et à atténuer facilement les vulnérabilités de votre code. Snyk prend en charge différents langages de programmation et s’intègre parfaitement à vos outils, pipelines et workflows. Commencez gratuitement avec Snyk dès aujourd’hui.
Enfin, suivez le guide des bonnes pratiques de sécurité Python de Snyk et développez vos compétences en sécurité des applications Python grâce au site gratuit Snyk Learn.



