L'écosystème Python est vaste, puissant et pratique, mais cette commodité comporte des risques de sécurité importants. Les attaques par chaîne d'approvisionnement, où les attaquants compromettent des bibliothèques tierces de confiance ou des environnements de construction pour injecter du code malveillant, deviennent de plus en plus courantes. En tant que développeurs Python, nous traitons souvent pyproject.toml et nos pipelines CI/CD comme de simples fichiers de configuration, mais ils constituent en réalité des surfaces d'attaque critiques. Cet article explore comment durcir ces zones pour protéger votre chaîne d'approvisionnement logicielle.
La vulnérabilité des systèmes de construction modernes
Les temps simples des scripts setup.py sont révolus. L'emballage Python moderne repose fortement sur des backends de construction tels que Poetry, PDM et Hatch. Ces outils automatisent la résolution des dépendances, la création d'environnements et la construction des packages. Bien que cela simplifie le développement, cela abstrait également une grande partie du processus, rendant l'audit plus difficile. Si un attaquant compromet un backend de construction populaire ou injecte un plugin malveillant, il peut exécuter du code arbitraire lors de la phase de construction, potentiellement en volant des secrets ou en modifiant l'artefact final avant qu'il n'atteigne un index de packages comme PyPI.
Le fichier pyproject.toml est la source de vérité pour ces outils. Il dicte quelles dépendances installer et comment construire le projet. Un pyproject.toml compromis peut entraîner :
- Confusion des dépendances : Les attaquants enregistrent des packages malveillants portant le même nom que des packages privés internes.
- Crochets malveillants : Scripts de construction personnalisés qui exfiltrent des données lors de l'installation.
- Typosquatting : Fautes de frappe intentionnelles de bibliothèques populaires que les utilisateurs installent par erreur.
Durcir pyproject.toml
Pour atténuer ces risques, vous devez traiter pyproject.toml avec la même rigueur que le code de production. L'une des pratiques les plus efficaces consiste à activer la résolution stricte des dépendances. De nombreux outils modernes vous permettent d'épingler les dépendances ou d'utiliser des fichiers de verrouillage (lock files). Engagez toujours votre fichier de verrouillage (par exemple, poetry.lock ou pdm.lock) dans le contrôle de version pour garantir des constructions reproductibles.
De plus, évitez d'utiliser * pour les exigences de version. Utilisez plutôt des contraintes de version sémantique aussi strictes que possible. Par exemple, au lieu de requests>=2.0, envisagez requests>=2.28.0, <3.0.0 si vous êtes confiant dans la stabilité de la version majeure.
Sécuriser les pipelines CI/CD
Les pipelines CI/CD sont les moteurs qui construisent et distribuent vos packages. Ils sont des cibles privilégiées pour les attaquants cherchant à injecter des logiciels malveillants dans les artefacts publiés. Voici les stratégies clés pour sécuriser votre pipeline :
1. Restreindre les permissions et utiliser le principe du moindre privilège
Vos runners CI doivent disposer des permissions minimales nécessaires pour construire le projet. N'utilisez jamais les accès root sauf en cas de nécessité absolue. Si vous utilisez GitHub Actions, assurez-vous que les secrets ne sont jamais exposés dans les journaux et que le workflow nécessite une approbation pour les modifications des branches protégées.
2. S'authentifier auprès des registres privés
Si votre organisation utilise des index de packages privés, assurez-vous que les jetons d'authentification sont rotés régulièrement et stockés en toute sécurité en tant que secrets CI/CD. Ne codez jamais les identifiants en dur dans votre pyproject.toml ou vos scripts.
Voici un exemple de la manière de référencer en toute sécurité les variables d'environnement dans un workflow GitHub Actions pour un outil comme Poetry :
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Poetry
run: curl -sSL https://install.python-poetry.org | python3 -
- name: Configure private registry credentials
run: |
poetry config http-basic.internal https "${{ secrets.PYPI_USERNAME }}" "${{ secrets.PYPI_PASSWORD }}"
- name: Install dependencies
run: poetry install --no-interaction
3. Valider les packages avant la publication
Avant de télécharger sur PyPI, validez votre package. Des outils comme twine check dist/* peuvent identifier d'éventuels problèmes avec les métadonnées. De plus, envisagez d'utiliser des outils de scan de sécurité automatisés dans votre pipeline qui vérifient les vulnérabilités connues dans vos dépendances. Des outils comme safety ou pip-audit peuvent être intégrés directement dans votre workflow CI.
steps:
- name: Audit dependencies
run: pip-audit -r requirements.txt
Conclusion
La sécurité de l'emballage Python n'est pas une configuration ponctuelle ; c'est un processus continu. En durcissant votre pyproject.toml, en imposant une gestion stricte des dépendances et en sécurisant vos pipelines CI/CD, vous réduisez considérablement le risque d'attaques par chaîne d'approvisionnement. Rappelez-vous que la sécurité est une responsabilité partagée. Maintenez vos outils à jour, surveillez les avis sur les dépendances et formez votre équipe aux risques associés aux logiciels open source. À une époque où les attaques par chaîne d'approvisionnement sont répandues, la défense proactive est votre meilleure protection.