# 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](#analyse-de-sécurité-bandit) 2. [Corrections appliquées](#corrections-appliquées) 3. [Bonnes pratiques de sécurité](#bonnes-pratiques-de-sécurité) 4. [Configuration des outils de sécurité](#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:** ```python # app/fiches/utils/fiche_utils.py:81 env = jinja2.Environment( autoescape=False, # Risque XSS potentiel ) ``` **Solution appliquée:** ```python # 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:** ```python 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:** ```python # 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:** ```python # 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:** ```python # 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:** ```python # 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:** ```python 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:** ```python # 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é ```python # 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:** ```bash pip install bandit ``` **Exécution:** ```bash # 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:** ```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):** ```python # 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`:** ```json { "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 - [Bandit documentation](https://bandit.readthedocs.io/) - [OWASP Top 10](https://owasp.org/www-project-top-ten/) - [Python Security Best Practices](https://python.readthedocs.io/en/latest/library/security_warnings.html) - [Requests Timeouts](https://requests.readthedocs.io/en/latest/user/advanced/#timeouts) --- ## Contact Pour signaler une vulnérabilité de sécurité, veuillez contacter l'équipe de développement en privé.