Code/docs/SECURITY.md
Stéphan Peccini cef9c9d67b
feat(security): Analyse et corrections de sécurité complète
Corrections de sécurité (Bandit):
- Fix vulnérabilité HIGH Jinja2 XSS avec documentation de sécurité
- Ajout timeouts sur toutes les requêtes HTTP (17 occurrences)
  * utils/gitea.py: 3 timeouts (10s)
  * app/fiches/interface.py: 1 timeout (10s)
  * scripts/auto_ingest.py: 2 timeouts (10-30s)
  * scripts/generer_analyse.py: 10 timeouts (10-120s)
  * Corpus/generer_analyse.py: 2 timeouts (30-120s)

Documentation et configuration:
- docs/SECURITY.md: Guide complet de sécurité avec analyse Bandit
- docs/GUIDE_GITDOC.md: Guide d'utilisation GitDoc pour autocommit
- Configuration GitDoc complète dans settings.json.example
- Configuration .gitignore pour .vscode/settings.json
- Recommandations extensions VSCode (SonarLint, Snyk, GitDoc)
- Mise à jour README avec statut sécurité

Résultats Bandit:
- 0 vulnérabilités HIGH
- 0 vulnérabilités MEDIUM
- Tests: 67 passent, couverture 16%

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-08 08:57:22 +01:00

7.8 KiB

Guide de sécurité

Ce document présente les pratiques de sécurité appliquées au projet FabNum et les résultats de l'analyse de sécurité.

Table des matières

  1. Analyse de sécurité Bandit
  2. Corrections appliquées
  3. Bonnes pratiques de sécurité
  4. Configuration des outils de sécurité

Analyse de sécurité Bandit

Bandit est un outil d'analyse statique de sécurité pour Python (SAST - Static Application Security Testing).

Résultats de l'analyse

État actuel (après corrections):

  • 7985 lignes de code analysées
  • 0 problème HIGH (critique)
  • 0 problème MEDIUM
  • 114 problèmes LOW (assertions dans les tests uniquement)

Détails des problèmes LOW

Les 114 problèmes LOW détectés sont tous des assertions dans les tests (B101):

  • Fichier: tests/unit/*.py
  • Nature: Utilisation de assert dans les tests
  • Impact: Non critique - Les assertions sont normales et acceptables dans les tests
  • Action: Aucune correction nécessaire

Corrections appliquées

1. Vulnérabilité HIGH corrigée: Jinja2 autoescape

Problème initial:

# app/fiches/utils/fiche_utils.py:81
env = jinja2.Environment(
    autoescape=False,  # Risque XSS potentiel
)

Solution appliquée:

# SECURITY NOTE: autoescape=False est approprié ici car :
# 1. Le template source est du Markdown (pas du HTML)
# 2. Les données proviennent de fichiers contrôlés (frontmatter), pas d'entrées utilisateur web
# 3. L'autoescape HTML casserait la syntaxe Markdown
# 4. Le rendu final est converti en HTML par un convertisseur Markdown séparé
env = jinja2.Environment(
    autoescape=False,  # nosec B701 - Safe for Markdown templates with controlled inputs
    undefined=jinja2.StrictUndefined,
    trim_blocks=True,
    lstrip_blocks=True,
)

Justification:

  • Le code traite des templates Markdown, pas HTML
  • Les données proviennent de fichiers contrôlés (metadata YAML), pas d'entrées utilisateur non fiables
  • L'autoescape HTML casserait la syntaxe Markdown
  • Le commentaire # nosec B701 supprime l'alerte Bandit pour ce cas légitime

2. Problèmes MEDIUM corrigés: Timeouts manquants (17 occurrences)

Problème initial:

response = requests.get(url)  # Pas de timeout = risque de blocage infini

Solution appliquée: Ajout de timeouts appropriés à tous les appels requests:

Fichier Type d'appel Timeout
utils/gitea.py API Gitea (GET fichiers) 10s
app/fiches/interface.py Téléchargement fiches 10s
scripts/auto_ingest.py POST upload fichiers 30s
scripts/auto_ingest.py GET liste documents 10s
scripts/generer_analyse.py POST IA génération 60-120s
scripts/generer_analyse.py GET/DELETE documents 10s
Corpus/generer_analyse.py POST IA analyse 120s

Exemples de corrections:

# Requêtes GET simples
response = requests.get(url, headers=headers, timeout=10)

# Upload de fichiers
response = requests.post(url, files=files, timeout=30)

# Requêtes IA longues
response = requests.post(api_url, json=payload, timeout=120)

Bénéfices:

  • Évite les blocages infinis en cas de serveur qui ne répond pas
  • Améliore la résilience de l'application
  • Protège contre les attaques par déni de service (DoS)

Bonnes pratiques de sécurité

1. Gestion des secrets

Configuration actuelle:

# config.py
GITEA_TOKEN = os.getenv("GITEA_TOKEN")

Recommandations:

  • Utiliser des variables d'environnement pour les secrets
  • Ne jamais committer .env dans git
  • Utiliser .env.local pour le développement local
  • Vérifier que .gitignore contient bien .env et .env.local

2. Validation des entrées utilisateur

Principes appliqués:

# Validation stricte avec Jinja2
env = jinja2.Environment(
    undefined=jinja2.StrictUndefined,  # Erreur si variable manquante
)

# Vérification des types
if not isinstance(file_path, (str, pathlib.Path)):
    raise TypeError("file_path doit être un str ou Path")

3. Timeouts sur les requêtes HTTP

Règle générale:

# MAUVAIS - Pas de timeout
response = requests.get(url)

# BON - Timeout adapté au type d'opération
response = requests.get(url, timeout=10)  # GET simple
response = requests.post(url, files=files, timeout=30)  # Upload
response = requests.post(url, json=data, timeout=120)  # Traitement IA long

4. Gestion des erreurs

Bonnes pratiques:

try:
    response = requests.get(url, timeout=10)
    response.raise_for_status()  # Lever une exception si erreur HTTP
except requests.Timeout:
    logger.error("Timeout lors de la requête")
except requests.RequestException as e:
    logger.error(f"Erreur réseau: {e}")

5. Logging sécurisé

Attention aux données sensibles:

# MAUVAIS - Log du token
logger.info(f"Token: {GITEA_TOKEN}")

# BON - Pas de données sensibles
logger.info(f"Requête à {url}")
logger.debug(f"Headers: {headers.keys()}")  # Clés seulement, pas les valeurs

6. Assertions dans le code de production

Règle:

  • assert dans les tests est acceptable (B101)
  • assert dans le code de production doit être évité
# MAUVAIS - assert en production
def process(data):
    assert data is not None  # Sera supprimé avec python -O

# BON - Validation explicite
def process(data):
    if data is None:
        raise ValueError("data ne peut pas être None")

Configuration des outils de sécurité

Bandit

Installation:

pip install bandit

Exécution:

# Analyse complète
bandit -r . --exclude './.venv,./venv,./pgpt,./IA,./batch_ia,./.git'

# Rapport JSON
bandit -r . -f json -o bandit-report.json --exclude './.venv,./venv,./pgpt,./IA,./batch_ia,./.git'

Configuration dans pyproject.toml:

[tool.bandit]
exclude_dirs = [".venv", "venv", "pgpt", "IA", "batch_ia", ".git", "tests"]
skips = ["B101"]  # Ignorer les assertions dans les tests

Suppression d'alertes spécifiques (à utiliser avec précaution):

# nosec B701 - Justification obligatoire
env = jinja2.Environment(autoescape=False)  # nosec B701 - Safe for Markdown

SonarQube (VSCode)

Extension: SonarSource.sonarlint-vscode

Configuration .vscode/settings.json.example:

{
  "sonarlint.rules": {
    "python:S1192": {
      "level": "off"
    }
  }
}

Snyk (VSCode)

Extension: snyk-security.snyk-vulnerability-scanner

Fonctionnalités:

  • Scan des dépendances pour détecter les vulnérabilités connues
  • Suggestions de mise à jour
  • Analyse du code

Utilisation:

  1. Installer l'extension Snyk dans VSCode
  2. Authentifier avec un compte Snyk (gratuit)
  3. Ouvrir le projet et lancer l'analyse

Checklist de sécurité pour les PR

Avant de soumettre une Pull Request, vérifier:

  • Aucun secret (tokens, mots de passe) dans le code
  • Tous les appels requests.* ont un timeout
  • Les entrées utilisateur sont validées
  • Les erreurs sont gérées proprement (try/except)
  • Les logs ne contiennent pas de données sensibles
  • Bandit ne détecte aucun problème HIGH ou MEDIUM
  • SonarQube ne signale pas de problèmes critiques
  • Les dépendances sont à jour (Snyk)

Ressources


Contact

Pour signaler une vulnérabilité de sécurité, veuillez contacter l'équipe de développement en privé.