Principales vulnérabilités de sécurité Python
Dans les pipelines de développement rapides d'aujourd'hui, un code Python non sécurisé peut introduire des risques sérieux. Python est apprécié pour sa simplicité, mais cette même flexibilité peut devenir dangereuse si les pratiques de codage sécurisé sont négligées. Des pièges d'injection de code aux bibliothèques tierces vulnérables, même une petite négligence peut ouvrir la porte aux attaquants. Des études récentes montrent des millions d'identifiants et de clés API accidentellement divulgués dans le code – un rappel brutal que la sécurité ne peut pas être une réflexion après coup. Dans cet article, nous détaillerons certaines des principales vulnérabilités de sécurité au niveau du langage Python (au-delà des simples problèmes de framework web), illustrerons leur impact avec des exemples concrets (y compris des CVE dans des bibliothèques populaires), et offrirons des conseils pour atténuer chaque risque. Nous soulignerons également comment l'intégration d'outils de sécurité (comme le SAST d'Aikido, l'analyse de secrets et les vérifications de dépendances) tôt dans votre workflow peut aider à détecter ces problèmes avant qu'ils ne fassent des ravages.
Les 10 principales vulnérabilités de sécurité Python
Vous trouverez ci-dessous dix des vulnérabilités de sécurité les plus courantes et les plus dangereuses dans les applications Python. Pour chacune, nous expliquons comment la vulnérabilité apparaît, son impact potentiel et comment la corriger ou la prévenir – en soulignant spécifiquement comment les outils de sécurité modernes peuvent être utiles.
1. Exécution de code arbitraire via eval() et exec()
Le eval() (et son cousin exec()) permet l'exécution dynamique de code Python à partir de chaînes de caractères. Utilisé de manière imprudente, eval peut transformer un simple script en une bombe à retardement. Si un attaquant peut influencer la chaîne passée à eval(), ils peuvent exécuter n'importe quel code de leur choix – de l'impression de données à la suppression de fichiers, ou pire. Comme l'a dit un développeur, « Le problème avec eval est qu'il risque de permettre aux attaquants de créer des entrées malveillantes... qui trompent votre programme pour qu'il exécute du code nuisible.. En d'autres termes, un eval(user_input) peut fonctionner aujourd'hui avec des entrées sûres, mais une entrée astucieusement conçue demain (comme __import__('os').system('rm -rf /')) pourrait effacer votre serveur.
Impact : L'exécution de code arbitraire est aussi grave qu'il y paraît – elle signifie un compromis complet de l'application. Les attaquants pourraient voler des données, les modifier ou prendre le contrôle de l'hôte. Ce n'est pas un cas limite théorique : de réelles violations se sont produites suite à une utilisation non sécurisée de eval. Même si votre utilisation de eval est « sûre » aujourd'hui (par exemple, en n'évaluant que des expressions mathématiques), elle crée une vulnérabilité latente que des changements futurs peuvent accidentellement déclencher.
Atténuation : N'utilisez jamais eval ou exec sur des entrées non fiables. En fait, évitez-les complètement, sauf en cas d'absolue nécessité. Python offre des alternatives plus sûres pour la plupart des cas d'utilisation (par exemple, utilisez l'évaluation littérale via ast.literal_eval pour la lecture de structures de données, ou des tables de dispatch pour l'appel de fonctions au lieu de construire une chaîne pour eval). Validez ou nettoyez toujours rigoureusement les entrées si une exécution dynamique est nécessaire.
Point d'attention Aikido Security : Un bon outil d'analyse statique (SAST) peut détecter l'utilisation de fonctions dangereuses. Le code scanning d'Aikido, par exemple, peut signaler les instances de eval() ou exec() dans votre code. Cela vous aide à identifier les chemins de code risqués lors d'une code review ou en CI – avant de elles n'atteignent la production. En intégrant une telle analyse dans votre pipeline, vous serez alerté chaque fois qu'une nouvelle utilisation de eval s'introduit, afin qu'il puisse être refactorisé ou examiné immédiatement.
2. Injection de commande OS via subprocess ou os.system
Dans la lignée du thème de l'injection de code, un autre piège critique est injection de commandes OS. Cela se produit lorsqu'un programme Python transmet une entrée utilisateur à des commandes shell système sans assainissement approprié. Des fonctions comme os.system(), subprocess.run() (avec shell=True), ou même l'utilisation de backticks/popen peut exécuter des commandes shell. Si des données contrôlées par l'utilisateur sont concaténées à ces commandes, un attaquant peut injecter des commandes malveillantes. Par exemple :
# Vulnerable snippet:filename = input("Enter the filename to delete: ")os.system(f"rm -f {filename}")
Un attaquant pourrait saisir file.txt; shutdown -h now et soudain notre script innocent exécute rm -f file.txt; shutdown -h now. Lors d'un incident réel, des attaquants ont exploité une vulnérabilité MLflow qui provenait du passage de données non assainies à un os.system appel à l'intérieur d'une fonction de prédiction. Comme le notent les chercheurs en sécurité de Snyk, l'injection de commandes permet l'exécution de commandes non autorisées, entraînant des fuites de données, des compromissions de systèmes et d'autres activités malveillantes.
Impact : L'injection de commandes OS peut être dévastatrice. Les attaquants peuvent enchaîner des commandes pour voler des fichiers sensibles (par exemple, lire la configuration de l'application ou les informations d'identification), créer des comptes utilisateur de porte dérobée, ou pivoter plus profondément dans le réseau. Étant donné que ces commandes s'exécutent avec les mêmes privilèges que votre processus Python, l'impact pourrait aller du vidage d'une base de données à la prise de contrôle complète du serveur. Les brèches rendues possibles par les injections de commandes entraînent souvent de graves dommages financiers et de réputation.
Atténuation : Ne jamais concaténer directement l'entrée utilisateur dans des commandes shell. Si vous devez appeler des programmes externes, utilisez les API plus sûres : le subprocess module vous permet de passer des arguments sous forme de liste (ce qui évite d'invoquer un shell réel). Par exemple, utilisez subprocess.run(["rm", "-f", filename]) au lieu de os.system("rm -f " + filename). Si vous utilisez subprocess avec shell=True est inévitable, assurez-vous que les entrées sont strictement validées ou nettoyées (par exemple, n'autorisez que les noms de fichiers alphanumériques attendus). De plus, envisagez d'utiliser des bibliothèques de haut niveau pour les tâches du système d'exploitation (par exemple, utilisez la gestion de fichiers de Python au lieu de rm pour supprimer un fichier).
Point d'attention Aikido Security : L'analyse statique du code d'Aikido inclut des règles pour détecter schémas d'injection de commandes. Il vous avertira s'il détecte quelque chose comme os.system(user_input) ou subprocess.Popen(..., shell=True) avec une entrée variable. En pratique, cela signifie que votre pipeline CI peut faire échouer un build si une utilisation dangereuse est introduite. En les détectant pendant le développement, vous évitez ce moment de « oups » où un extrait de débogage oublié ou un appel shell rapide et sale devient une porte ouverte pour les attaquants.
3. Secrets codés en dur dans le code
Le codage en dur de secrets – tels que les clés API, les identifiants, les jetons ou les clés privées – dans le code source est une pratique omniprésente et dangereuse. C'est facile à faire (« mettez juste la clé AWS ici pour l'instant… »), mais difficile à annuler, car les secrets peuvent persister dans l'historique des commits même après leur suppression. Les secrets exposés sont une mine d'or pour les attaquants. En fait, les fuites de secrets ont explosé récemment : en 2022, une analyse des dépôts GitHub publics a révélé 10 millions de secrets exposés en seulement 1 an (une augmentation de 67 % par rapport à l'année précédente). Ceux-ci ne sont pas seulement commis par des développeurs juniors – cela se produit à tous les niveaux. Une fois divulgués, les secrets ont été utilisés dans des violations majeures (par exemple, un attaquant a utilisé des identifiants d'administrateur codés en dur dans le code pour pénétrer les systèmes internes d'Uber).
Impact : Si un attaquant trouve un secret (dans un dépôt public, une sauvegarde divulguée, une image Docker, etc.), il peut souvent pivoter directement dans vos systèmes. Imaginez un mot de passe de base de données codé en dur – s'il est divulgué, un attaquant pourrait se connecter à votre base de données et extraire des données utilisateur. Les clés API cloud codées en dur sont encore pires : les fournisseurs de cloud signalent que les identifiants exposés sont généralement exploités en quelques minutes après leur découverte par des bots scannant les dépôts. Le rayon d'action peut inclure la compromission complète de l'environnement cloud, des factures cloud élevées pour les mineurs de crypto-monnaie, ou un accès non autorisé à des services sensibles. Les secrets sont véritablement « les clés du royaume », les divulguer, c'est comme laisser votre porte d'entrée déverrouillée aux cambrioleurs.
Mesures d'atténuation : Ne jamais commettre de véritables secrets dans le code. Utilisez plutôt des fichiers de configuration, des variables d'environnement ou des services de gestion de secrets (comme HashiCorp Vault, AWS Secrets Manager, etc.) pour injecter les secrets au moment de l'exécution. Si vous devez inclure une information d'identification par défaut ou un exemple dans le code, assurez-vous qu'il s'agit d'un substitut non-production. Effectuez une analyse régulière des secrets sur votre base de code et son historique ; si un secret s'y glisse, révoquez-le immédiatement (c'est-à-dire invalidez-le et remplacez-le) et purgez le commit si possible. Appliquez le principe du moindre privilège – même si un secret est divulgué, un jeton en lecture seule est moins dommageable qu'une clé d'administrateur complète.
Point d'attention Aikido Security : C'est là que les outils de détection de secrets excellent. L'analyse des secrets d'Aikido (inspirée par des acteurs comme GitGuardian et d'autres) recherchera automatiquement des motifs tels que les clés API, les identifiants, les certificats, et plus encore dans vos dépôts. Elle peut vous alerter dès qu'un développeur commet accidentellement un secret. L'intégration d'un tel outil dans votre CI/CD (ou même des hooks de pré-commit) signifie qu'une clé AWS codée en dur est signalée avant même d'atteindre GitHub. La plateforme d'Aikido offre même une remédiation automatique – par exemple, en révoquant l'identifiant exposé et en guidant le développeur vers l'utilisation d'une méthode de stockage sécurisée.
4. Désérialisation Insecure (Abus de Pickle)
Le module pickle de Python offre un moyen de sérialiser et de désérialiser des objets complexes. Cependant, pickle est notoirement peu sûr par conception. La désérialisation de données provenant d'une source non fiable peut exécuter du code arbitraire pendant le processus de désérialisation. La documentation Python elle-même est très claire à ce sujet : “Le module pickle n'est pas destiné à être sécurisé contre les données malveillantes. Ne jamais désérialiser des données reçues d'une source non fiable ou non authentifiée.” En pratique, cela signifie que si un attaquant peut fournir à votre application un pickle (par exemple, un cookie forgé ou un objet mis en cache), il pourrait exécuter n'importe quel code Python sur votre serveur – il s'agit essentiellement d'une vulnérabilité RCE (exécution de code à distance) pré-authentification.
Exemple concret : Un développeur pourrait utiliser pickle.loads() sur des données reçues via un réseau (pensant peut-être que c'est juste un moyen pratique de transmettre des objets Python). Les attaquants peuvent créer une charge utile pickle qui, une fois déserialisée, exécute des commandes système. Des chercheurs en sécurité ont démontré des exploits triviaux où la désérialisation d'un objet apparemment inoffensif déclenche un reverse shell vers l'attaquant. Dans un cas, un exploit de 15 lignes utilisant pickle a suffi à générer un shell, car l'application faisait aveuglément confiance aux données pickle sur le réseau.
Impact : La désérialisation non sécurisée est un problème critique – menant généralement à une exécution de code à distance complète. Étant donné que pickle peut invoquer n'importe quelle classe et méthode lors du chargement, un attaquant peut en abuser pour supprimer des fichiers, installer des logiciels malveillants ou pivoter vers d'autres services internes. Contrairement à certaines vulnérabilités qui ne font que fuir des données, celle-ci donne un contrôle direct à l'attaquant. L'impact est limité uniquement par les permissions de l'application en cours d'exécution (et souvent les applications Python s'exécutent avec de nombreux privilèges).
Atténuation : N'utilisez pas pickle (ou une sérialisation similaire comme marshal) sur des données provenant de sources non fiables. Si vous devez échanger des données entre systèmes, utilisez des formats sécurisés comme JSON ou XML – et même dans ce cas, soyez prudent (validez les entrées). Pour les cas d'utilisation spécifiques à Python (partage d'objets), envisagez jsonpickle en mode sécurisé ou d'autres sérialiseurs plus sûrs, mais supposez toujours que l'entrée peut être hostile. Si vous devez absolument accepter des données pickle (par exemple, pour la compatibilité), traitez-les comme du code : exigez une authentification, utilisez des signatures numériques pour vous assurer qu'elles proviennent d'une source fiable, ou exécutez la désérialisation dans un sandbox avec des privilèges restreints. Le conseil le plus simple est généralement le meilleur : éviter complètement la désérialisation dynamique des entrées utilisateur.
Point d'attention Aikido Security : Les scanners de code modernes peuvent détecter l'utilisation d'API dangereuses comme pickle.loads ou pickle.load sur des données potentiellement externes. Le moteur SAST d'Aikido, par exemple, effectue des vérifications pour la désérialisation non sécurisée – il sait que toute invocation de pickle est un signal d'alarme, sauf preuve du contraire. Il les mettra en évidence lors des code reviews. De plus, le scanner de dépendances d'Aikido suit les CVE de désérialisation connues. Par exemple, certaines bibliothèques (ou frameworks) ont présenté des failles de désérialisation (pas seulement pickle – même des éléments comme XML ou YAML, que nous aborderons ensuite). Aikido vous alertera si vous utilisez une version vulnérable d'une telle bibliothèque et suggérera des mises à niveau ou des correctifs.
5. Chargement YAML non sécurisé (Vulnérabilité PyYAML)
Les problèmes de sérialisation ne se limitent pas à pickle. YAML, un format de données convivial, peut également poser problème s'il est utilisé de manière non sécurisée. La populaire bibliothèque PyYAML présentait une faille bien connue : l'utilisation de yaml.load() sur une entrée non fiable pouvait exécuter des objets Python arbitraires. En fait, la fonction de PyYAML load() était fondamentalement aussi puissante que pickle. CVE-2017-18342 a été attribué à ce problème – « Dans PyYAML avant la version 5.1, l'API yaml.load() pouvait exécuter du code arbitraire si elle était utilisée avec des données non fiables. » La correction a consisté à introduire un safe_load fonction et rendre load() passent par défaut en mode sécurisé dans les versions plus récentes. Mais de nombreuses applications peuvent encore utiliser par inadvertance l'ancienne yaml.load (ou une ancienne version de PyYAML), pensant qu'ils ne font que parser une configuration, alors qu'en réalité un attaquant pourrait créer un YAML qui exécute du code.
Impact : Similaire à pickle, l'impact est l'exécution de code à distance. Par exemple, un fichier YAML peut intégrer un objet Python d'un type qui, lors de sa construction, exécute un appel système. Les attaquants exploitant cela peuvent faire en sorte que votre application exécute des commandes du système d'exploitation au moment où elle tente de parser un YAML malveillant. Cela peut être exploité via toute fonctionnalité qui parse du YAML fourni par l'utilisateur (les scénarios courants incluent les importateurs de configuration, le templating Kubernetes en CI/CD, ou les applications web qui acceptent des entrées YAML). La CVE ci-dessus a été marquée Critique (CVSS 9.8) précisément en raison de la facilité avec laquelle elle pouvait être déclenchée et de la gravité du résultat.
Atténuation : Utilisez toujours chargement sécurisé méthodes pour les formats de données. Dans PyYAML, utilisez yaml.safe_load() for any content that is not fully trusted. This mode only parses basic YAML types (strings, ints, lists, dicts) and will refuse to instantiate custom objects. If you are on PyYAML < 5.1, upgrade the library – the old load() est carrément dangereux. De même, méfiez-vous des autres formats de sérialisation : utilisez json.loads (JSON n'a pas d'exécution de code par conception, ce qui est une bonne chose), ou si vous utilisez pickle-like alternatives, assurez-vous qu'elles disposent d'un mode sécurisé. Une idée de défense en profondeur : exécutez l'analyse dans un environnement à faibles privilèges ou un sandbox si possible (ainsi, même si le code s'exécute, il ne peut pas causer beaucoup de dommages).
Point d'attention Aikido Security : analyse des dépendances is key here. Aikido’s dependency analyzer would flag that you have PyYAML <5.1 in your requirements, warning you of CVE-2017-18342 and advising an upgrade. On the code side, Aikido’s SAST can also catch usage of yaml.load(...) et suggérer d'utiliser safe_load à la place. Il s'agit de détecter le problème à deux niveaux : assurez-vous d'utiliser une version de bibliothèque sécurisée et veillez à appeler les fonctions sûres. En intégrant ces vérifications, vous seriez averti pendant le développement que « attention, cet appel d'analyse YAML est dangereux » avec des conseils pour le corriger.
6. Traversée de répertoire via des opérations de fichiers non sécurisées (Tarfile Extraction)
La manipulation de fichiers est courante en Python (par exemple, le dépaquetage d'archives téléchargées par l'utilisateur). Mais des opérations de fichiers naïves peuvent introduire vulnérabilités de parcours de chemin. Un exemple notable est le module intégré de Python tarfile module. Il a été révélé que pendant plus de 15 ans, tarfile.extractall() était vulnérable à une attaque par traversée de chemin (surnommée une “vulnérabilité vieille de 15 ans” lors de sa redécouverte). Si une archive tar malveillante contient des entrées de fichiers avec ../ dans leurs noms, extractall écrirait volontiers des fichiers en dehors du répertoire prévu, potentiellement en écrasant des fichiers système critiques. Ceci est suivi comme CVE-2007-4559. Bien qu'il s'agisse d'une ancienne CVE, il reste non corrigé dans la bibliothèque standard de Python à ce jour, et une recherche en 2022 a montré des centaines de milliers de dépôts utilisent encore tarfile de manière vulnérable.
Un attaquant pourrait télécharger ou fournir un fichier tar spécialement conçu de telle sorte que, lorsque votre code l'extrait, il implante une charge utile (par exemple, un web shell ou une configuration écrasée) dans un emplacement auquel l'attaquant ne devrait pas avoir accès. Dans une démonstration, des chercheurs ont exploité cela pour obtenir une exécution de code en écrasant le propre code d'un package Python après l'extraction.
Il ne s'agit pas seulement de fichiers tar – des problèmes similaires peuvent survenir avec des fichiers zip (vulnérabilité zip slip) ou toute opération de fichier où vous construisez des chemins à partir d'une entrée externe. Sans vérifications appropriées, une entrée d'archive nommée ../../../../../etc/passwd écrira dans /etc/passwd lors de l'extraction.
Impact : La traversée de chemin peut mener à écriture de fichier arbitraire (ou lire, dans certains cas) sur le serveur. L'écriture de fichiers au mauvais endroit peut mener à l'exécution de code – par exemple, en écrasant la configuration d'une application pour qu'elle pointe vers du code contrôlé par l'attaquant, ou en déposant un binaire troyen dans le PATH. Même si cela ne mène pas immédiatement à l'exécution de code à distance (RCE), l'écrasement de fichiers critiques peut saboter l'intégrité du système ou faciliter des attaques ultérieures. Considérez les conséquences si un attaquant écrasait le/la de votre application .env fichier ou un script qui est exécuté – ils pourraient insérer des commandes malveillantes. Dans le cas de CVE-2007-4559, la communauté a rehaussé sa gravité lorsqu'il a été démontré que l'exécution de code est souvent une conséquence directe de l'exploitation de l'écrasement de fichier.
Atténuation : N'extrayez jamais d'archives provenant de sources non fiables sans validation. Pour tarfile, utilisez tarfile.extractall(path, members=...) et filtrer manuellement les membres. Vous pouvez implémenter une vérification pour vous assurer qu'aucun chemin de fichier de membre ne se trouve en dehors du répertoire cible (par exemple, en résolvant les chemins absolus et en vérifiant les motifs de traversée). La documentation Python inclut désormais un extrait de code pour ce faire en toute sécurité – rejetant essentiellement tout fichier avec .. ou les préfixes de lecteur. Alternativement, envisagez d'utiliser des bibliothèques tierces qui effectuent une extraction sécurisée. Pour les fichiers zip, inspectez de manière similaire les noms avant l'écriture, ou utilisez des bibliothèques qui atténuent le zip slip. Toujours le moindre privilège : si possible, exécutez l'extraction dans un sandbox ou un répertoire avec des permissions limitées. De cette façon, même si un exploit tente de s'échapper, il ne pourra pas atteindre les fichiers critiques du système.
Point d'attention Aikido Security : L'analyse statique d'Aikido peut détecter des schémas dangereux tels que tarfile.extractall() utilisation sans filtrage sécurisé des membres. Il connaît CVE-2007-4559 et peut signaler les instances dans votre code où vous appelez extractall ou extract sans précautions. Cela sert d'incitation à mettre en œuvre les vérifications appropriées. De plus, le flux d'intelligence sur les vulnérabilités d'Aikido (sa recherche interne) assure le suivi de ces problèmes « latents » dans les bibliothèques standard et les packages populaires. En analysant votre code et vos dépendances, il affichera un avertissement tel que « Potentiel path traversal dans l'utilisation de tarfile – envisagez de valider le contenu de l'archive », en renvoyant à des conseils de bonnes pratiques. En bref, cela aide les développeurs à détecter un bug vieux de 15 ans qui pourrait autrement passer inaperçu dans leur code.
7. Utilisation de bibliothèques obsolètes avec des vulnérabilités connues (Requests, urllib3, etc.)
Le riche écosystème de packages de Python est l'une de ses forces – mais chaque dépendance que vous incluez peut également introduire des vulnérabilités si elle n'est pas maintenue à jour. Les bibliothèques Python de premier plan ont eu leur lot de CVE. Par exemple, la bibliothèque HTTP Requests largement utilisée a présenté des bugs tels que :
- CVE-2023-32681 – où Requests divulguerait des identifiants de proxy HTTP dans certains scénarios de redirection, en envoyant
Proxy-Authorizationdes en-têtes aux serveurs de destination et exposant potentiellement des informations sensibles info. (Ceci a été corrigé dans Requests 2.31.0.) - CVE-2024-35195 – une faille logique où, si vous désactiviez la vérification du certificat SSL une fois dans une session, Requests ignorerait persistamment la vérification pour les requêtes ultérieures vers le même hôte, même si vous tentiez de la réactiver. Essentiellement, une fois cassé, toujours cassé – une mauvaise surprise qui pourrait laisser les connexions non sécurisées en silence. Corrigé dans la version 2.32.0.
- Injection CRLF dans urllib3 – urllib3 (utilisé par Requests en arrière-plan) présentait une vulnérabilité permettant l'injection CRLF dans les en-têtes HTTP si un attaquant contrôlait une partie de l'URL ou de la méthode de la requête (par exemple, des caractères de nouvelle ligne pouvaient être insérés dans un en-tête). Cela pourrait être exploité pour faire passer des en-têtes ou diviser des réponses, conduisant potentiellement au détournement de session ou à la manipulation des caches web. (Plusieurs CVE, par exemple CVE-2019-9740 pour urllib intégré de Python, ont été attribuées à de tels problèmes.)
Ce ne sont là que quelques exemples. D'autres cas notables incluent des vulnérabilités dans Analyse d'URL (par exemple, CVE-2023-24329, un problème dans urllib.parse qui permettait aux attaquants de contourner les listes de blocage d'URL en utilisant une URL astucieuse commençant par un espace ou un caractère de contrôle), et des problèmes dans gestion des paquets outils (comme l'ancienne vulnérabilité de pip CVE-2018-20225 qui permettait à un téléchargement malveillant d'écraser des fichiers arbitraires). Même les bibliothèques de données populaires (Pandas, NumPy) ont occasionnellement des correctifs de sécurité (souvent des problèmes de DoS ou de corruption de mémoire).
Impact : Les vulnérabilités connues dans les bibliothèques peuvent avoir un large éventail d'impacts – de la fuite d'informations et du déni de service à la compromission totale – selon la faille. Le point clé est que les attaquants recherchent activement les applications utilisant des versions obsolètes. Si vous utilisez une ancienne version de Requests et que votre application effectue des appels réseau, un attaquant pourrait exploiter la fuite d'authentification proxy pour voler des identifiants. Ou si vous avez un urllib3 obsolète, il pourrait exploiter une injection CRLF pour corrompre vos interactions HTTP. Étant donné que ces vulnérabilités sont publiques, les attaquants savent exactement quoi rechercher. Ne pas mettre à jour les dépendances, c'est comme laisser des failles connues non corrigées dans votre application.
Atténuation : Restez informé des mises à jour des dépendances et des avis de sécurité. Utilisez des outils pour vérifier les CVE connues dans vos dépendances (pip-tools, Dependabot de GitHub, ou des outils SCA commerciaux). Lorsqu'une nouvelle CVE critique est annoncée (par exemple, une faille grave dans Django, Flask, Requests, etc.), priorisez la mise à niveau vers une version corrigée. Dans la mesure du possible, épinglez vos dépendances à des versions éprouvées et examinez les journaux de modifications des mises à jour. Envisagez également des épinglages de version minimaux : par exemple, exiger requests>=2.31.0 si vous savez que les versions plus anciennes sont vulnérables. De plus, employez une défense en profondeur : par exemple, même si Requests avait un bug de vérification de certificat, vous pourriez ajouter une couche de sécurité réseau (comme l'interception TLS ou l'épinglage de certificats supplémentaires) pour atténuer le risque. Mais le plus simple est : maintenez vos paquets à jour.
Appel àAikido : C'est ici que analyse de la composition logicielle SCA)Aikido en jeu. Le scanner de dépendances Aikidovérifie en permanence les exigences de votre projet (et même vos dépendances transitives) par rapport à une base de données de vulnérabilités connues. Il vous alertera en indiquant « La bibliothèque X version Y est vulnérable à CVE-2023-32681 », en fournissant souvent des détails et une version corrigée recommandée. Mieux encore, la plateforme Aikidopeut effectuer des corrections automatisées, par exemple en ouvrant une demande de modification pour passer à une version supérieure. En intégrant cela à votre CI/CD, vous vous assurez de ne pas déployer de conteneurs ou d'applications avec des bibliothèques obsolètes. En bref, des outils tels Aikido vous Aikido détecter les CVE connues et même Aikido les corriger automatiquement, complétant ainsi les scanners open source avec des règles personnalisées et des informations à jour.
8. Désactivation des fonctionnalités de sécurité (par exemple, ignorer la validation des certificats SSL)
Parfois, en développement ou en test, les ingénieurs désactivent des contrôles de sécurité importants – et le code est ensuite déployé en production de cette manière. Un exemple classique en Python est l'envoi de requêtes HTTP avec Vérification SSL désactivée. La bibliothèque Requests (et d'autres comme urllib3) permettent un verify=False flag pour ignorer les erreurs de certificat SSL. C'est pratique pour gérer les certificats auto-signés dans un environnement de développement, mais si cela arrive en production, cela vous expose à des attaques de l'homme du milieu (MitM). La documentation de Requests avertit explicitement : lorsque verify=False, le client acceptera tout certificat – ignorant les non-correspondances de noms d'hôte ou les certificats expirés/auto-signés – rendant votre application vulnérable aux attaques MITM. En substance, vous ne confirmez plus que vous communiquez avec le véritable serveur. Un attaquant pourrait intercepter votre trafic (surtout s'il peut usurper le DNS ou se trouve sur le même réseau) et présenter n'importe quel certificat pour détourner la connexion.
Au-delà de la vérification SSL, d'autres fonctionnalités désactivées peuvent également vous causer des problèmes : par exemple, l'utilisation de HTTP au lieu de HTTPS pour les communications sensibles, la désactivation manuelle de la vérification du nom d'hôte TLS, ou la désactivation des filets de sécurité intégrés de Python (comme l'exécution de l'interpréteur avec les assertions désactivées si ces assertions protégeaient un contrôle critique pour la sécurité).
Impact : Si un attaquant peut s'interposer dans votre trafic (ce qui est plus facile que beaucoup ne le pensent, en particulier dans les réseaux cloud ou de conteneurs, ou les Wi-Fi publics, etc.), il peut décrypter et modifier les données en transit lorsque la vérification du certificat est désactivée. Cela pourrait signifier qu'un attaquant vole des jetons API, injecte des réponses malveillantes ou usurpe des services. Dans une architecture de microservices, un service compromis ou un point d'ancrage réseau pourrait permettre un pivotement en interceptant les appels d'un service à l'autre si ces appels ne sont pas correctement vérifiés. Nous avons également vu des scénarios où la désactivation de la vérification SSL dans une bibliothèque cliente API a permis à des attaquants de distribuer des malwares depuis ce qui aurait dû être un serveur de mise à jour de confiance, simplement en utilisant un certificat auto-signé sur un domaine usurpé. Les conséquences peuvent être le vol de données, la prise de contrôle de compte, ou l'injection de données/commandes malveillantes dans le fonctionnement de votre application.
Atténuation : Ne désactivez jamais la vérification SSL dans le code de production. Si vous devez absolument (par exemple, vous connecter à un service interne avec un certificat auto-signé), alors au moins épinglez le certificat ou l'empreinte numérique afin de ne pas faire aveuglément confiance à n'importe quel certificat. Mieux encore, utilisez une CA privée et rendez vos certificats internes fiables en fournissant le bundle de CA. Pendant le développement, si vous utilisez verify=False, soyez extrêmement prudent de le supprimer avant de committer ou d'utiliser la configuration pour ne le désactiver que dans les environnements hors production. Les code review devraient considérer verify=False comme un signal d'alarme majeur. De plus, envisagez d'utiliser des outils comme les linters pour interdire ce flag dans le code committé. Il en va de même pour d'autres raccourcis – par exemple, ne pas intercepter et ignorer les exceptions de sécurité, ne pas désactiver l'authentification ou le CSRF en mode debug et oublier de les réactiver, etc.
Point d'attention Aikido Security : Les scanners d'Aikido peuvent détecter l'utilisation de paramètres risqués comme verify=False dans les requêtes. En fait, il peut appliquer des politiques (similaires au fonctionnement des politiques Prisma/Checkov) pour s'assurer qu'aucun code ne désactive les vérifications de certificat. Si un tel schéma est trouvé, Aikido le signalera dans les résultats du scan, le traitant comme une vulnérabilité. Il pourrait indiquer « Vérification du certificat SSL désactivée ici – ceci ne devrait pas être utilisé en production » avec un lien vers la ligne de code. En intégrant cela dans le CI, vous prévenez efficacement le scénario « J'ai laissé un flag de debug activé ». De plus, l'analyse des dépendances mentionnée précédemment vous informera également de bugs comme CVE-2024-35195, où même une désactivation involontaire persiste – soulignant que vous devez mettre à jour votre bibliothèque pour restaurer entièrement la sécurité.
9. Packages malveillants ou compromis (attaques de la chaîne d'approvisionnement logicielle)
Toutes les menaces ne proviennent pas d'erreurs dans votre propre code – parfois le code que vous avez extrait de PyPI lui-même est l'attaque. attaques de la chaîne d’approvisionnement via des paquets Python malveillants ont augmenté ces dernières années. Les attaquants publient des paquets avec des fautes de frappe (typo-squatted) ou carrément faux sur PyPI, en les nommant de manière similaire à des bibliothèques populaires (par exemple, requêtes au lieu de requests) ou des noms attrayants comme free-net-vpn. Des développeurs peu méfiants les installent, et le code malveillant s'exécute lors de l'installation (dans setup.py) ou lors de l'importation. Par exemple, en 2022, dix paquets PyPI malveillants ont été découverts qui ont usurpé l'identité de bibliothèques courantes et ont injecté des malwares voleurs d'informations dans les systèmes des développeurs. Un package, imitant un package bien connu, a été conçu pour rechercher les identifiants AWS et les envoyer à un attaquant via un webhook Discord. Un autre appelé WINRPCexploit prétendait être un outil d'exploit mais exfiltrait en réalité toutes les variables d'environnement (contenant souvent des secrets) vers l'attaquant.
Même des packages légitimes peuvent être compromis si un attaquant accède au compte du mainteneur (comme cela s'est produit avec event-stream dans Node.js, et également en Python). Il y a eu des cas où des packages largement utilisés ont été brièvement détournés pour inclure du code malveillant dans de nouvelles versions. Par exemple, un package pourrait soudainement commencer à envoyer des données de télémétrie d'utilisation (espionnage) ou inclure une porte dérobée déclenchée sous certaines conditions.
Impact : L'impact des packages malveillants peut être grave et de grande portée. Étant donné que ces packages exécutent souvent du code au moment de l'installation (via des scripts de configuration) ou lors de leur importation, ils peuvent faire tout ce que votre utilisateur peut faire : voler des identifiants (à partir de fichiers de configuration, de variables d'environnement, de la configuration AWS CLI, etc.), installer des chevaux de Troie, chiffrer des fichiers (ransomware) ou ouvrir des shells inversés. Et parce qu'ils s'exécutent souvent avec les privilèges du développeur, cela peut compromettre non seulement l'application, mais aussi l'ensemble du système ou les identifiants de ce développeur. Dans un pipeline CI, un package empoisonné pourrait exfiltrer des secrets de votre environnement CI. Dans un environnement de production, une dépendance malveillante pourrait devenir une porte dérobée permettant aux attaquants de l'exploiter en continu. Les attaques de la chaîne d’approvisionnement sont particulièrement insidieuses car elles sapent la confiance dans les outils mêmes que nous utilisons.
Atténuation : Examinez et surveillez attentivement vos dépendances. Quelques bonnes pratiques : Épinglez les dépendances à des versions spécifiques (afin de ne pas télécharger automatiquement une mise à jour altérée). Vérifiez les sommes de contrôle ou les signatures des paquets (PyPI prend désormais en charge la signature GPG et des mécanismes similaires, bien que tous les paquets ne l'utilisent pas). Utilisez des outils comme pip install --no-build-isolation --only-binary=:all: pour les "wheels" reconnus comme sûrs afin d'éviter d'exécuter le setup.py de paquets inconnus. Envisagez d'employer un proxy ou un miroir PyPI local et n'autorisez que les paquets vérifiés. Lisez toujours les détails du paquet : si requests a 100 millions de téléchargements et soudain il y a un nouveau requêtes paquet – c'est suspect. Les fonctionnalités de sécurité de PyPI (comme la 2FA pour les mainteneurs) s'améliorent, mais la responsabilité incombe également aux utilisateurs : n'installez pas de paquets aléatoires sans examen minutieux. Si possible, examinez la source des nouvelles dépendances (au moins une analyse rapide pour des motifs malveillants évidents comme os.system('curl ...')).
Point d'attention Aikido Security : La plateforme d'Aikido s'attaque aux risques de la chaîne d'approvisionnement de plusieurs manières. Premièrement, son analyse des dépendances signalera les packages connus comme étant des malwares ou ayant un comportement suspect. Aikido ingère en continu le renseignement sur les menaces (indicateurs de packages malveillants) et peut vous avertir, « Le package X est signalé comme malveillant – ne l'utilisez pas. » Deuxièmement, Aikido SafeChain (un outil open-source d'Aikido) peut empêcher l'installation de packages non fiables. Il bloque essentiellement les packages qui n'ont pas suffisamment vieilli ou qui apparaissent soudainement dans votre arbre de dépendances, atténuant les attaques de typosquatting en exigeant une période de « latence » (par exemple, n'installer que les packages qui existent depuis plus de 24 heures, pour éviter les malwares fraîchement publiés). En intégrant ces défenses, vous ajoutez un chien de garde automatisé chaque fois que vous effectuez pip install. En effet, Aikido aide à garantir que les bibliothèques dont vous dépendez ne vous trahissent pas – en détectant les acteurs malveillants connus et en appliquant des politiques pour rendre plus difficile l'introduction de nouveaux.
10. Pratiques cryptographiques faibles (aléatoire insuffisant et mauvaise utilisation de la cryptographie)
La cryptographie est complexe, et son utilisation incorrecte peut compromettre la sécurité autant qu'un bug manifeste. En Python, une erreur courante est d'utiliser le mauvais générateur de nombres aléatoires pour des contextes sensibles à la sécurité. Par exemple, les développeurs pourraient utiliser random.random() ou random.randrange() pour générer un jeton de réinitialisation de mot de passe ou un ID de session. Cependant, le module standard random est, tout comme , non cryptographiquement sécurisé. – il utilise des algorithmes prévisibles non adaptés à la génération de secrets. Python a introduit le module secrets pour cette raison, déclarant que secrets devrait être utilisé pour la génération de nombres aléatoires critiques pour la sécurité de préférence au générateur de nombres pseudo-aléatoires par défaut dans le random module, qui est conçu pour la modélisation et la simulation, et non pour la sécurité ou la cryptographie. Si vous utilisez random pour les jetons, un attaquant pourrait être en mesure de prédire les valeurs (étant donné suffisamment d'observations ou la connaissance de la graine).
Une autre pratique faible est l'utilisation d'algorithmes obsolètes ou faibles. Par exemple, l'utilisation de MD5 ou SHA1 pour le hachage de mots de passe (les deux sont considérés comme cassés à cette fin) ou l'absence totale de salage des mots de passe. Ou la création de votre propre « chiffrement » (par exemple, un schéma XOR maison) au lieu d'utiliser des bibliothèques éprouvées. Ces faiblesses peuvent ne pas se manifester comme une CVE dans votre code, mais elles abaissent considérablement la barre pour les attaquants. Un exemple concret : si les mots de passe sont stockés sans salage avec SHA-1, un attaquant qui vole la base de données de hachages peut déchiffrer la plupart des mots de passe rapidement en utilisant des tables arc-en-ciel précalculées.
Impact : Un aléatoire non sécurisé pourrait conduire au détournement de compte ou à la falsification de jetons. Imaginez qu'un attaquant devine des cookies de session parce qu'ils ont été dérivés d'une sortie PRNG prévisible – ce n'est pas seulement théorique, cela s'est produit dans des systèmes mal conçus. Un hachage ou un chiffrement faible signifie que si un attaquant viole une couche (par exemple, obtient un accès en lecture à une base de données ou intercepte le trafic chiffré), il peut facilement déchiffrer ou casser les données prétendument protégées. Globalement, une cryptographie faible donne un faux sentiment de sécurité ; les attaquants pourraient ne pas avoir besoin d'un « exploit » lorsqu'ils peuvent simplement forcer ou prédire ce dont ils ont besoin.
Atténuation : Suivez les bonnes pratiques cryptographiques. Utilisez le secrets module ou os.urandom() pour générer des jetons secrets, des clés ou des nonces. Utilisez des bibliothèques de haut niveau pour le chiffrement (comme Fernet dans la cryptography bibliothèque) plutôt que d'écrire votre propre cryptographie. Pour le stockage des mots de passe, utilisez des KDF établis (bcrypt, Argon2, PBKDF2 avec des itérations adéquates) – jamais de hachages simples sans sel. Maintenez les algorithmes à jour ; par exemple, SHA-256 est bon pour l'intégrité, mais pour les mots de passe, vous voudriez toujours un hachage lent comme bcrypt. Et activez toujours TLS pour la communication réseau, en utilisant des protocoles modernes (TLS 1.2+). Essentiellement, préférez les implémentations bien éprouvées aux approches personnalisées ou héritées. De plus, restez attentif aux dépréciations : si un paramètre ou un chiffrement SSL/TLS n'est plus recommandé (le module ssl de Python met généralement à jour les valeurs par défaut, mais soyez vigilant si vous surchargez les paramètres).
Point d'attention Aikido Security : Le SAST d'Aikido peut aider à repérer certaines erreurs cryptographiques – par exemple, il peut avertir s'il détecte le random module utilisé là où secrets serait approprié, ou s'il détecte l'utilisation de MD5 dans un contexte de sécurité. De plus, l'intelligence des vulnérabilités d'Aikido vous alertera si vous utilisez un algorithme faible connu dans un contexte ayant eu des CVEs antérieures (par exemple, si une bibliothèque que vous utilisez est configurée par défaut en mode non sécurisé, Aikido pourrait le signaler). Bien que la supervision humaine soit cruciale en cryptographie, disposer d'un outil automatisé pour une double vérification ne fait pas de mal. C'est comme un linter pour la sécurité : si vous commettez par inadvertance token = random.random(), un outil peut dire « Êtes-vous sûr ? Ce n'est pas cryptographiquement sécurisé. » Ce type de retour d'information précoce peut orienter les développeurs vers les bons modules (suggérant même peut-être : import secrets et secrets.token_hex() comme alternative). En somme, Aikido contribue à faire respecter l'hygiène cryptographique en détectant les schémas faibles évidents et en vous tenant informé des vulnérabilités liées à la cryptographie dans l'écosystème.
Conclusion : Sécurisez votre code Python dès le départ
La flexibilité et le riche écosystème de Python peuvent être une arme à double tranchant – puissants entre les mains des développeurs, mais offrant de nombreuses voies aux attaquants si des précautions adéquates ne sont pas prises. Nous avons exploré comment des éléments tels que l'exécution de code dynamique, les vulnérabilités par injection, les secrets divulgués, les dépendances obsolètes et d'autres pièges peuvent compromettre la sécurité de vos applications Python. La bonne nouvelle est que chacun de ces défauts est évitable grâce à une combinaison de bonnes pratiques et d'outils appropriés :
- Adoptez des pratiques de codage sécurisé : validez les entrées, évitez les fonctions dangereuses et utilisez des valeurs par défaut sûres (par exemple, des chargeurs sûrs, des nombres aléatoires sécurisés, des algorithmes mis à jour).
- Maintenez vos dépendances à jour et vérifiées : ne laissez pas les CVEs connues persister dans vos exigences, et soyez prudent quant à ce que vous installez.
- Intégrez la sécurité dans votre pipeline de développement : cela signifie exécuter des analyses statiques, des scans de secrets et des audits de dépendances pendant que vous codez et pendant l'intégration continue (CI), et non après un incident.
DevSecOps modernes telles que Aikido peuvent grandement faciliter ce processus en automatisant la détection de ces problèmes : détection d'un mot de passe codé en dur avant qu'il ne quitte votre ordinateur portable, blocage du déploiement d'un package vulnérable, alerte en cas de faille récemment découverte dans l'une de vos bibliothèques. Comme l'indique sécurité des conteneurs Red Hat sécurité des conteneurs , près de la moitié des équipes perdent le sommeil à cause de la sécurité des conteneurs (et, par extension, des logiciels) ; il en va probablement de même pour la sécurité des applications Python. En déplaçant la sécurité vers la gauche, c'est-à-dire en la traitant dès le début du développement, vous pouvez réduire considérablement les risques d'urgence nocturne causée par un bug Python évitable.
En résumé, rester informé et proactif est essentiel. Continuez à vous former sur le codage sécurisé (le Guide de sécurité Python et les ressources OWASP sont excellents), encouragez les code review en gardant la sécurité à l'esprit, et utilisez des outils automatisés comme filet de sécurité. Les développeurs Python qui intègrent la sécurité dès le départ feront économiser du temps, de l'argent et de la réputation à leurs organisations sur le long terme. Écrivons du code qui n'est pas seulement intelligent et propre, mais aussi sûr et sécurisé. Votre futur vous (et vos utilisateurs) vous en remercieront.
Continuer la lecture :
Top 9 Docker sécurité des conteneurs
Les 7 principales vulnérabilités Cloud
Les 10 principales vulnérabilités de sécurité des applications Web que chaque équipe devrait connaître
Top 9 sécurité Kubernetes et erreurs de configuration sécurité Kubernetes
Les principales vulnérabilités de sécurité du code présentes dans les applications modernes Top des vulnérabilités de sécurité JavaScript dans les applications Web modernes
sécurité de la chaîne d’approvisionnement logicielle 9 principales sécurité de la chaîne d’approvisionnement logicielle expliquées

