Sécuriser les secrets de test avec pytest-mask-secrets

WBOY
Libérer: 2024-08-12 18:43:59
original
469 Les gens l'ont consulté

Securing Testing Secrets with pytest-mask-secrets

Garder la sécurité et la confidentialité des données sensibles est une priorité absolue dans le développement de logiciels. Les journaux d’applications, l’un des vecteurs de fuite les plus courants, sont soigneusement gardés pour éviter la présence de secrets. Les mêmes préoccupations et risques s’appliquent également aux journaux de tests, qui peuvent révéler des mots de passe ou des jetons d’accès. Les outils exécutant des flux de travail CI fournissent généralement des mécanismes permettant de masquer les données sensibles dans les journaux avec peu ou pas d'effort. Bien que cela soit très pratique, efficace et facile à utiliser, dans certaines situations, cela peut ne pas suffire.

Pourquoi le masquage des flux de travail CI seul pourrait ne pas suffire

Par exemple, GitHub Actions fait un bon travail en matière de gestion des secrets. Tout secret défini dans le flux de travail est automatiquement masqué de la sortie capturée, ce qui fonctionne à merveille. Cependant, comme tout système CI, il a ses limites. Si le rapport de sortie emprunte un chemin différent (par exemple, s'il est enregistré dans un fichier, si Junit est généré ou envoyé à un magasin de journaux distant), GitHub Actions n'a pas la possibilité d'inspecter le contenu et de masquer les secrets.

De plus, les tests ne s'exécuteront pas toujours dans le cadre d'un flux de travail CI, et même dans ce cas, les secrets devront peut-être être cachés. Imaginez que vous exécutez des tests localement et partagez un journal pour discuter d'un problème. Sans vous en rendre compte, vous incluez une URL avec votre jeton d'accès.

Par conséquent, disposer d'un mécanisme permettant de gérer les données sensibles dans les journaux de test est essentiel à tous les niveaux. La meilleure approche consiste à implémenter cela directement au niveau du test ou dans le cadre de test lui-même. Cela garantit que les secrets ne sont pas divulgués à partir de la source principale, empêchant ainsi leur transmission à travers le système.

Ajouter une protection au bon niveau

Maintenir le masquage des secrets directement dans les tests peut être relativement coûteux et sujet aux erreurs, et ressemble souvent à une bataille perdue d'avance. Par exemple, imaginez que vous deviez concevoir une URL avec un jeton comme paramètre. Cette URL doit être rendue différemment pour être utilisée dans une requête par rapport à sa présence dans le journal.

En revanche, l'interception de la génération du rapport dans le cadre de test offre une opportunité idéale de s'accrocher au processus et de modifier les enregistrements pour éliminer les données sensibles. Cette approche est transparente pour les tests, ne nécessite aucune modification du code de test et fonctionne exactement comme la fonctionnalité de masquage des secrets dans les workflows CI : exécutez-la simplement et oubliez la gestion des secrets. Il automatise le processus, garantissant que les données sensibles sont protégées sans ajouter de complexité supplémentaire à la configuration du test.

C'est exactement ce que fait pytest-mask-secrets, évidemment lorsque pytest est utilisé pour l'exécution de tests. Parmi ses nombreuses fonctionnalités, pytest propose un système de plugins riche et flexible. À cette fin, il vous permet de vous connecter au processus juste avant la génération d'un journal, à un moment où toutes les données ont déjà été collectées. Cela facilite la recherche et la suppression des valeurs sensibles des enregistrements avant leur sortie.

Le mettre à l'épreuve : une démo pratique

Pour illustrer comment cela fonctionne, un exemple simple sera le plus efficace. Vous trouverez ci-dessous un test trivial qui ne représente peut-être pas un scénario de test réel, mais sert à démontrer assez bien les secrets du masque pytest.

import logging
import os


def test_password_length():
    password = os.environ["PASSWORD"]
    logging.info("Tested password: %s", password)
    assert len(password) > 18
Copier après la connexion

Dans cet exemple, il y a une assertion qui a le potentiel d'échouer (et elle échouera), ainsi qu'un message de journal qui inclut un secret. Oui, cela peut sembler idiot d'inclure un secret dans le journal, mais envisagez un scénario dans lequel vous avez une URL avec un jeton comme paramètre et où la journalisation de débogage détaillée est activée. Dans de tels cas, les bibliothèques telles que les requêtes pourraient par inadvertance enregistrer le secret de cette manière.

Maintenant, place aux tests. Tout d'abord, définissez le secret nécessaire à des fins de test :

(venv) $ export PASSWORD="TOP-SECRET"
Copier après la connexion

Ensuite, lancez le test :

(venv) $ pytest --log-level=info test.py 
============================= test session starts ==============================
platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0
rootdir: /tmp/tmp.AvZtz7nHZS
collected 1 item                                                               

test.py F                                                                [100%]

=================================== FAILURES ===================================
_____________________________ test_password_length _____________________________

    def test_password_length():
        password = os.environ["PASSWORD"]
        logging.info("Tested password: %s", password)
>       assert len(password) > 18
E       AssertionError: assert 10 > 18
E        +  where 10 = len('TOP-SECRET')

test.py:8: AssertionError
------------------------------ Captured log call -------------------------------
INFO     root:test.py:7 Tested password: TOP-SECRET
=========================== short test summary info ============================
FAILED test.py::test_password_length - AssertionError: assert 10 > 18
============================== 1 failed in 0.03s ===============================
Copier après la connexion

Par défaut, la valeur secrète apparaît deux fois dans la sortie : une fois dans le message de journal capturé et de nouveau dans l'assertion ayant échoué.

Mais que se passe-t-il si pytest-mask-secrets est installé ?

(venv) $ pip install pytest-mask-secrets
Copier après la connexion

Et configuré en conséquence. Il doit connaître la liste des variables d'environnement qui contiennent les secrets. Cela se fait en définissant la variable MASK_SECRETS :

(venv) $ export MASK_SECRETS=PASSWORD
Copier après la connexion

Maintenant, relancez le test :

(venv) $ pytest --log-level=info test.py 
============================= test session starts ==============================
platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0
rootdir: /tmp/tmp.AvZtz7nHZS
plugins: mask-secrets-1.2.0
collected 1 item                                                               

test.py F                                                                [100%]

=================================== FAILURES ===================================
_____________________________ test_password_length _____________________________

    def test_password_length():
        password = os.environ["PASSWORD"]
        logging.info("Tested password: %s", password)
>       assert len(password) > 18
E       AssertionError: assert 10 > 18
E        +  where 10 = len('*****')

test.py:8: AssertionError
------------------------------ Captured log call -------------------------------
INFO     root:test.py:7 Tested password: *****
=========================== short test summary info ============================
FAILED test.py::test_password_length - AssertionError: assert 10 > 18
============================== 1 failed in 0.02s ===============================
Copier après la connexion

Désormais, au lieu de la valeur secrète, des astérisques apparaissent partout où le secret aurait été imprimé. Le travail est terminé et le rapport de test est désormais exempt de données sensibles.

Pensées finales

D'après l'exemple, il peut sembler que pytest-mask-secrets ne fait pas grand-chose de plus que ce que GitHub Actions fait déjà par défaut, ce qui rend l'effort redondant. Cependant, comme mentionné précédemment, les outils d'exécution de flux de travail CI masquent uniquement les secrets dans la sortie capturée, laissant les fichiers JUnit et autres rapports inchangés. Sans pytest-mask-secrets, des données sensibles pourraient toujours être exposées dans ces fichiers : cela s'applique à tout rapport généré par pytest. D'un autre côté, pytest-mask-secrets ne masque pas la sortie directe lorsque l'option log_cli est utilisée, les fonctionnalités de masquage des workflows CI sont donc toujours utiles. Il est souvent préférable d’utiliser les deux outils conjointement pour assurer la protection des données sensibles.

Ça y est. Merci d'avoir pris le temps de lire cet article. J'espère que cela a fourni des informations précieuses sur l'utilisation de pytest-mask-secrets pour améliorer la sécurité de votre processus de test.

Bon test !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!