Baseline de sécurité
Aperçu
Une référence complète se trouve dans references/baseline.md (sections §0–§18, cherchez par ## N.). Ce fichier est la procédure opérationnelle. Principe fondamental : adapter la rigueur au niveau de menace, puis prouver chaque constat par une preuve. Trois lois : ne jamais faire confiance au client, ne jamais faire confiance au code du modèle, ne jamais faire confiance aux valeurs par défaut.
Choisir le mode
| Demande | Mode | À lire dans baseline.md |
|---|---|---|
| « Planifier / démarrer un projet de manière sécurisée », rédiger des règles d’agent | Plan | §0, §2, §3, §16 |
| « Auditer / revoir cette application / ce dépôt / cette PR » | Revue de code | §1.3, §4–§11, §15.2 |
| « Auditer mon serveur / homelab / VPS », « est-il à jour ? » | Audit hôte | §3.3, §8.3, §12, §13 |
| « Nous avons été piratés / nous avons divulgué une clé » | Incident | §17, §8.2 |
Un audit hôte inclut une courte revue de code de chaque application exposée sur Internet qui gère des comptes ou des données personnelles.
Étape 1 — Classifier le niveau (toujours en premier, l’indiquer dans le rapport)
Décider à partir de faits observables, pas de ce que le propriétaire appelle le projet :
| Niveau | Prédicat | Appliquer |
|---|---|---|
| T0 Jouet | Pas d’utilisateurs réels ni de données ET pas accessible depuis Internet (LAN uniquement, ou derrière un SSO) | §2, §8 |
| T1 Public, sans compte | Accessible depuis Internet, pas de connexion, pas de données personnelles stockées | T0 + §9, §10 |
| T2 Comptes / données utilisateur | Connexion quelconque, données personnelles (noms, emails, listes d’invités), clé API ou jeton détenu | Tout |
| T3 Argent / données sensibles à grande échelle / réglementé | Paiements, santé, coffres d’identifiants, finance, données de plus de 1 000 personnes, contrats clients | T2 + revue externe + §14 |
Un hôte homelab est évalué au niveau le plus élevé de tout ce qu’il exécute. Un agrégateur d’identifiants (gestionnaire de mots de passe, n8n, Home Assistant, Portainer, détenteur de docker.sock) est classé T3 par rayon d’explosion.
Étape 2 — Collecter des preuves (lecture seule)
Exécutez les scripts fournis via bash. Sur un hôte distant, transférez-les via SSH : ssh host 'bash -s -- --remote-digests' < scripts/audit-docker-host.sh et ssh host 'bash -s -- <project-dir>' < scripts/scan-code.sh.
bash scripts/audit-docker-host.sh --remote-digests— Correctifs OS, indicateur de redémarrage, sockets en écoute, pare-feu, sshd, utilisateur/privilege/ports publiés/docker.sock de chaque conteneur, NOMS de variables d’environnement suspectes, fraîcheur des images (UP-TO-DATE / OUTDATED / local-build).bash scripts/scan-code.sh <project-dir>— Repérer les secrets, injections, XSS, affectations massives, ID de locataire fournis par le client, captures par défaut, chiffrement faible, fichiers lock, risques Dockerfile/compose, inventaire des routes.
Ensuite, faire ce que les scripts ne peuvent pas :
- Inventaire du proxy inverse : lister chaque nom d’hôte public, sa cible, et si l’authentification se trouve devant (NPM DB / Caddy / étiquettes Traefik). Les interfaces d’administration (liste §3.3) sur un nom d’hôte public sans SSO/ liste d’accès = constat.
- Vue externe : depuis l’extérieur du réseau local,
curl -sI https://<host>pour les en-têtes (§10.2), et sonder/.env,/.git/config,/admin,/apiavec GET uniquement. - Trace d’autorisation pour chaque application T2+ : pour chaque route, nommer le contrôle d’autorisation et d’où vient l’identifiant principal/locataire (§4.3). Appliquer la question §1.3.
- Confiance du proxy : si une application lit
X-Forwarded-For, vérifier quel saut elle considère comme fiable ($proxy_add_x_forwarded_forajoute ; la première valeur est contrôlée par l’attaquant). - Force des identifiants par rôle : pour chaque rôle (admin, personnel, bénévole, jeton API/MCP), trouver comment son secret est défini, y compris les voies d’initialisation, héritage et migration qui contournent la vérification normale de longueur. Vérifier la longueur réelle des valeurs de
.envavecawk -F= '{print $1, length($2)}', jamais en les affichant. Un secret faible associé à une limite de taux contournable constitue un seul constat, pas deux. - Versions vs avis de sécurité : pour chaque application exposée sur Internet, comparer la version en cours d’exécution avec la version actuelle et les CVE connues. Utiliser une recherche web pour les avis de sécurité du produit.
Porte de l’hôte (la checklist §16 est par projet ; utilisez-la pour un hôte)
- Chaque nom d’hôte public est listé, et chaque interface d’administration (§3.3) dispose d’un SSO, d’une liste d’accès ou d’un VPN devant, ou n’est pas publique
- Hyperviseur, Docker, admin NPM/proxy, admin du coffre de mots de passe : jamais publics
- Inscription ouverte désactivée sur chaque application auto-hébergée qui n’en a pas besoin (Vaultwarden, Open WebUI, Gitea, Immich, …)
- Ports accessibles depuis le WAN = seulement 80/443 (+ VPN). Les ports publiés par Docker contournent ufw : vérifier les redirections du routeur et
DOCKER-USER - Le proxy transmet une IP client que les applications ne peuvent pas tromper (§4.5, X-Forwarded-For)
- Membres du groupe docker listés ; chacun équivaut à root
- Fichiers secrets en mode 600 ; pas de
.env/clés lisibles par tous - OS patché, aucun redémarrage en attente de plus de 7 jours ; images à jour (tableau de fraîcheur)
- Sauvegardes récentes et une restauration testée (§13.4)
Règles d’engagement
- Lecture seule par défaut. Pas d’écriture, de redémarrage, de mise à jour, de POST modifiant des données, de force brute, ni de scan d’hôtes que le propriétaire ne possède pas.
- Ne jamais afficher les valeurs secrètes. Signaler uniquement le nom de la variable et le fichier:ligne.
- Inspecter les magasins de configuration (tables de configuration de base de données, paramètres JSON, env de
docker inspect) par clés et longueurs uniquement :jq 'paths',SELECT key FROM …,awk -F= '{print $1, length($2)}'. Ne jamais vider une ligne ou un fichier de configuration entier pour l’examiner : il contiendra des clés API. - Les changements (mises à jour, chmod, corrections de configuration) n’interviennent qu’après le rapport, et uniquement si le demandeur les a sollicités. Pour les mises à jour, suivre « Mise à jour sécurisée » ci-dessous.
Étape 3 — Rapport (cette forme exacte)
- Périmètre et niveau : ce qui a été examiné, le niveau, et la raison en une ligne.
- Verdict : une phrase — déployer / corriger d’abord / stopper.
- Constatations, classées Critique → Faible. Chaque constat comporte : titre,
CONFIRMÉ(vous l’avez reproduit ou lu le code/chemin de configuration exact) ouPISTE(plausible, non prouvé), preuve (fichier:ligne, commande + extrait de sortie), impact en une phrase, correction. - Tableau de fraîcheur (audit hôte) : composant, version en cours, dernière version, risque de la mise à jour.
- Couverture : les sections de la porte §16 que vous avez vérifiées, et celles que vous n’avez pas vérifiées avec la raison. Le silence n’est pas un laissez-passer.
- Actions suivantes, numérotées, du moindre effort au plus fort risque d’abord.
Mise à jour sécurisée (« s’assurer que tout est à jour »)
- Confirmer qu’une sauvegarde existe et est récente (§13.4). Enregistrer l’ID d’image actuel de chaque conteneur pour pouvoir revenir en arrière avec
image: <repo>@<ancien digest>. - Sans état (stateless) = pas de volume nommé ni de montage bind sur lequel l’application écrit, et pas de base de données. Les sites nginx statiques, gotenberg, flaresolverr sont sans état. En cas de doute, traiter comme porteur de données.
- Classifier : porteur de données ou avec migration de schéma (bases de données, Immich, Paperless, Vaultwarden, Firefly, n8n, Home Assistant) → un par un, lire d’abord les notes de version pour les changements cassants. Sans état (sites nginx statiques, outils) → par lot.
- Ne jamais sauter une version majeure de base de données (postgres 15→17) via
docker pull. Cela nécessite une sauvegarde / restauration. docker compose pull && docker compose up -dpar projet, puis vérifier l’état : statut du conteneur, logs pour les erreurs, et une vérification HTTP de l’URL publique.- Les constructions locales (
local-build) se mettent à jour en reconstruisant avec--pull. Les paquets OS nécessitent sudo ; si vous n’en avez pas, signaler la liste et l’indicateur de redémarrage. - Si les pulls échouent avec
429 toomanyrequests, arrêter. Demanderdocker loginsur l’hôte, ou réessayer après 6 h. Ne pas boucler.
Erreurs courantes
| Erreur | Correct |
|---|---|
| Tout signaler comme « Élevé » | Sévérité = exploitabilité × niveau × rayon d’explosion |
| Considérer un résultat de script comme un constat | Le résultat du script est une PISTE tant que vous n’avez pas lu le code |
| « Le conteneur s’exécute en tant que root » sans vérifier | De nombreuses images réduisent les privilèges dans l’entrée ; vérifier ps à l’intérieur |
| « Le port 9000 est ouvert » sur un hôte LAN | Dire qui peut y accéder : LAN uniquement, WAN via redirection du routeur, ou via proxy |
| Sauter le niveau et auditer un site statique comme une banque | Niveau d’abord ; T1 nécessite des en-têtes et des dépendances, pas du RLS |
Tout mettre à jour avec :latest en une seule fois | Un service porteur de données à la fois, avec un digest de retour arrière |
Corriger en désactivant le contrôle (RLS désactivé, CORS *) | Corriger la politique, jamais la supprimer (§7.2) |