xpeditis2.0/docs/security/check-secu/REMEDIATION-2026-09-10.md
2026-09-14 11:19:29 +02:00

6.6 KiB
Raw Permalink Blame History

Corrections supplémentaires — 10 septembre 2026

Branche check_secu. Les modifications antérieures sont conservées. Deux problèmes supplémentaires ont été traités successivement ; aucun commit, déploiement, accès à une base réelle ou envoi d’email réel n’a été effectué.

1. SMTP : certificat non vérifié et STARTTLS facultatif

Résultat local : corrigé (fixed).

L’unique transport Nodemailer désactivait rejectUnauthorized. La production et la préproduction utilisent le port 587 avec SMTP_SECURE=false, donc STARTTLS plutôt que TLS implicite. Sans requireTLS, un serveur ou intermédiaire refusant STARTTLS pouvait conduire à une authentification sans chiffrement. Les messages concernés comprennent les liens de réinitialisation et d’invitation.

Le correctif dans apps/backend/src/infrastructure/email/email.adapter.ts active la vérification des certificats et impose STARTTLS lorsque NODE_ENV=production. Le nom SMTP d’origine reste utilisé pour vérifier le certificat après résolution de l’adresse IP. Le TLS implicite et les serveurs SMTP locaux de développement sans TLS restent supportés ; cette exception de développement ne doit pas servir en production.

Preuve : email.adapter.spec.ts contient quatre tests. Un serveur SMTP éphémère sur loopback, qui n’annonce pas STARTTLS et refuse sa commande, est rejeté avant AUTH. Le contrôle local explicitement sans TLS peut s’authentifier sur ce même serveur simulé. Les options de vérification de certificat, le nom d’origine, le TLS implicite et la propagation d’un échec d’envoi sont vérifiés. Aucun email n’est transmis.

Limite : le rejet d’un certificat SMTP invalide est vérifié via les options de transport et une erreur d’envoi simulée, pas par une connexion au fournisseur réel. Une investigation indépendante et une revue du correctif n’ont retenu aucun contournement confirmé.

2. PostgreSQL : paramètres TLS incohérents entre clients

Résultat local : corrigé (fixed). Déploiement conditionné à la configuration de confiance.

L’API et le script de démarrage ignoraient DATABASE_SSL, tandis que la CLI TypeORM acceptait les certificats non authentifiés. La configuration de production exige pourtant hostssl. Outre l’absence de vérification d’identité côté CLI, cette incohérence pouvait empêcher le démarrage de l’API face à la configuration PostgreSQL fournie.

Une fonction commune databaseTlsOptions est désormais utilisée par :

  • la configuration TypeORM de l’API dans app.module.ts ;
  • la source de données de la CLI TypeORM ;
  • les clients de disponibilité et de migration de scripts/setup/startup.js ;
  • le script scripts/setup/run-migrations.js ;
  • le client du script d’entrypoint historique, bien que l’image actuelle utilise startup.js.

Lorsque DATABASE_SSL=true, tous ces clients vérifient le certificat et l’identité de DATABASE_HOST, y compris une adresse IP. DATABASE_SSL_CA accepte le certificat public PEM de confiance pour le certificat auto-signé déjà généré par l’infrastructure. L’absence de CA spécifique conserve les autorités reconnues par Node ; elle n’entraîne jamais une désactivation de la vérification. Une valeur de drapeau invalide est refusée. Les chaînes majuscules/minuscules suivent le comportement de validation Joi. Le mode local explicitement sans TLS reste disponible.

Les chemins des scripts ont également été alignés sur la racine backend : copie Docker à /app/startup.js et copie du dépôt sous scripts/setup. Les modules compilés, entités et migrations sont ainsi résolus au même endroit. Le chargement de startup.js depuis un test n’établit aucune connexion et ne lance pas de migration.

Preuves :

  • 11 tests dans database-tls.spec.ts : drapeaux de configuration et véritables handshakes TLS locaux avec certificat de test éphémère. Le certificat approuvé avec le SAN correspondant à l’IP est accepté ; un certificat non approuvé ou une IP incorrecte sont refusés.
  • 2 tests dans database-startup.spec.ts : mêmes paramètres SSL transmis au client de disponibilité et aux deux scripts de migration, dans les dispositions Docker et dépôt. PostgreSQL et TypeORM sont simulés, aucune migration réelle n’est exécutée.
  • Chargement du script avec le helper réellement compilé : réussi, sans connexion.
  • Investigation et revue indépendantes : aucun contournement ou régression confirmé. Le reviewer était limité par le sandbox pour ses handshakes ; les handshakes du parent ont été exécutés avec autorisation sur loopback et ont réussi.

Avant déploiement : renseigner DATABASE_SSL_CA dans le Secret backend SOPS avec le certificat public de db-01 récupéré via un canal d’administration authentifié. Ne jamais copier sa clé privée. L’API et le Job de migration consomment ce même Secret. Le gabarit de secrets et le README de production décrivent cette préparation. Aucun certificat de production n’a été lu ou modifié. Ne pas déployer le nouveau client contre un certificat auto-signé sans avoir distribué cette confiance.

Les scripts ponctuels de maintenance hors des chemins de démarrage n’ont pas tous été harmonisés ; leur revue reste à effectuer avant une utilisation sur une base TLS.

Vérifications finales

  • npm test -- --runInBand (backend) : 451 tests réussis, 5 tests déjà ignorés, 32 suites réussies et 1 ignorée. Les tests réseau utilisent uniquement des serveurs éphémères sur 127.0.0.1.
  • npm run build (backend) : réussi.
  • ESLint sur les fichiers TypeScript concernés : réussi.
  • Vérifications de syntaxe Node des deux scripts de démarrage/migration : réussies.
  • Vérification de syntaxe de l’entrypoint shell : réussie.
  • git diff --check : réussi.

Les essais ont détecté puis permis de corriger une configuration de test masquée par NODE_ENV=test, ainsi qu’un type TLS trop large pour les options TypeORM. Aucun contrôle de sécurité n’a été assoupli pour contourner ces échecs.

Analyse des dépendances en attente

La tentative initiale de npm audit --package-lock-only --omit=dev --json n’a pas pu joindre le registre npm (ENOTFOUND). La demande d’accès réseau a ensuite été refusée par la validation automatique : la liste des dépendances et versions aurait été envoyée vers une destination externe non explicitement autorisée.

Une demande d’autorisation est en attente. Aucun contournement ni nouvel envoi n’a été effectué. Cette analyse ne transmettrait ni le code source ni les fichiers .env. L’audit exhaustif du dépôt et des dépendances n’est donc toujours pas déclaré terminé.