1
Sécurité
Antoine Van Elstraete edited this page 2026-09-08 18:04:51 +02:00

Sécurité

Principes

Le projet applique trois règles absolues pour protéger les secrets :

  • Aucun secret en clair : ni dans le code source, ni dans les logs, ni dans les messages d'erreur, ni dans les fixtures de test.
  • Masquage systématique : utiliser redact_url(), redact_secrets() et redact_exception() depuis utils/redaction.py.
  • Chaînage d'exceptions : ne jamais conserver une exception externe brute comme __cause__ ou __context__. Journaliser la version expurgée puis utiliser raise ... from None, ou chaîner une cause elle-même expurgée.

Masquage des données sensibles

Masquage des URLs

La fonction redact_url() masque les paramètres sensibles dans les URLs. Les clés sensibles (insensibles à la casse) sont : icalsecurise, token, key, password, secret. Elle utilise urlsplit/urlunsplit/parse_qsl pour reconstruire l'URL. En cas d'erreur de parsing, elle retourne REDACTED_URL.

Masquage des secrets dans le texte

La fonction redact_secrets() masque les URLs et les tokens isolés dans un texte. Elle traite les motifs comme : icalsecurise=XXX, token=XXX, password=XXX, secret=XXX. Les secrets supplémentaires (extra_secrets) sont triés par longueur décroissante pour éviter les masquages partiels.

Masquage des exceptions

La fonction redact_exception(exc, extra_secrets=()) applique redact_secrets au message de l'exception et aux secrets configurés. La méthode Settings.redaction_secrets() retourne un tuple de tous les secrets configurés (mots de passe, clés API) à transmettre.

Configuration des logs

Le formatter RedactingFormatter dans utils/logging.py masque les secrets dans tous les enregistrements de log :

  • Masquage de record.msg
  • Masquage de record.args (gère les tuples et les dictionnaires)
  • setup_logging() configure un handler stdout avec ce formatter
  • Les loggers tiers (urllib3, slixmpp) sont positionnés sur WARNING

Types sécurisés

Les mots de passe et clés API utilisent pydantic.SecretStr :

  • Ils ne sont jamais sérialisés en clair.
  • Ils sont masqués dans les messages d'erreur Pydantic (hide_input_in_errors pour les paramètres XMPP).

Vérification avant déploiement

Règles de détection

Le script scripts/check_secrets.py analyse le dépôt pour détecter les secrets littéraux avec trois motifs regex :

  • Affectation littérale : key = "value" ou key: "value" (valeur de 3+ caractères entre guillemets)
  • Affectation non quotée : pour les fichiers de configuration (.conf, .ini, .toml, .yaml, .yml), key = value (valeur de 3+ caractères non quotée)
  • Paramètre d'URL : ?token=XXX ou &api_key=XXX (valeur de 3+ caractères)

Exclusions

Le script exclut :

  • Les répertoires .git, .venv, .worktrees, __pycache__
  • Les fichiers .env (jamais versionnés)
  • Le fichier GUIDE_DEV_PYTHON.md (exemples intentionnels)
  • Le répertoire tests/
  • Les lignes marquées avec secret-check: allow (liste blanche locale pour les fixtures/exemples)

Utilisation

# Vérifier tout le dépôt
python scripts/check_secrets.py

# Vérifier uniquement les fichiers indexés (avant un commit)
python scripts/check_secrets.py --staged

Les codes de sortie sont :

  • 0 : aucun secret détecté
  • 1 : secrets trouvés
  • 2 : erreur lors de l'exécution

Les résultats n'exposent jamais la valeur détectée, seulement le chemin, le numéro de ligne et le nom de la règle.

Tests de non-fuite

La suite de tests inclut des tests de non-fuite obligatoires :

  • Injecter des valeurs sentinelles distinctes dans l'URL, les identifiants, le mot de passe et la clé API
  • Provoquer une erreur externe
  • Vérifier l'absence dans :
    • Le message d'erreur
    • Les logs
    • __cause__ et __context__
    • Le traceback complet

Chaque secret utilise une sentinelle distincte pour identifier précisément toute fuite éventuelle.

Fichier .env

Le fichier .env n'est jamais commité (couvert par .gitignore). Utiliser .env.example comme modèle. En production, le fichier doit être local et lisible uniquement par le compte de service :

sudo install -d -m 0700 -o <service-user> -g <service-group> <config-dir>
sudo install -m 0600 -o <service-user> -g <service-group> .env <env-file>

Bonnes pratiques

  • Ne jamais placer de secrets dans les unités systemd, les commandes shell ou les journaux système.
  • Éviter de partager les exports de logs sans revue : les données sensibles de l'environnement ou des outils tiers ne doivent pas être supposées sûres par défaut.
  • Après modification des identifiants, relancer check_secrets.py et un --dry-run avant de redémarrer le service.
  • En cas d'échec, ne pas redémarrer automatiquement après modification des identifiants : corriger la configuration, relancer les vérifications, puis consulter le journal expurgé.

Voir aussi : Configuration pour les variables d'environnement, Déploiement pour la configuration en production.