Sécurité
Signaler une vulnérabilité en privé et renforcer une installation : accès, sessions, secrets et données conservées.
Signaler une vulnérabilité
Signalez toute vulnérabilité supposée en privé via GitHub : ouvrez l’onglet Security du dépôt Tournevia et choisissez Report a vulnerability (signalement privé de vulnérabilités GitHub). N’ouvrez pas de ticket, de pull request ou de discussion publics au sujet d’une vulnérabilité supposée.
Indiquez le commit ou le kit concerné, les étapes de reproduction avec des données fictives et l’impact observé. Les signalements sont traités en privé. Aucun délai de réponse n’est garanti.
Versions prises en charge
Tournevia Community est un logiciel en préversion, sans version prise en charge à ce jour. Les correctifs de sécurité sont apportés sur la branche principale uniquement ; les kits construits à partir de commits antérieurs ne sont pas corrigés.
Ce qu’il ne faut pas communiquer
- N’incluez jamais de données clients, d’identifiants, de cookies de session ni de détails d’un déploiement que vous n’exploitez pas.
- Testez uniquement avec des données fictives, ou sur des déploiements que vous êtes explicitement autorisé à tester.
- Laissez le temps de corriger avant de publier des détails.
Liste de contrôle du déploiement
- L’accès d’une équipe utilise le mode partagé en HTTPS, avec un certificat reconnu par les navigateurs des utilisateurs. N’exposez jamais le mode local sur Internet.
- Seul le proxy HTTPS est publié ; derrière un proxy HTTPS existant, rien n’est publié et seul le serveur web
edgerejoint le réseau de ce proxy. La base, l’API et le routeur restent privés ; la surcouche de routage place le routeur sur un réseau interne. Une connexion HTTP simple vers un routeur distant transmettrait les coordonnées des livraisons en clair. - Le dossier privé (
workspace.env,workspace.json,private-setup.url) et les sauvegardes ne sont lisibles que par les opérateurs et ne sont jamais versionnés. - Le lien de première utilisation sert une seule fois à l’opérateur et n’est jamais communiqué aux exploitants.
MONITOR_TOKENn’est défini que si un outil de supervision interroge/api/v1/metrics.TRUST_PROXY_CLIENT_HEADERreste désactivé derrière un proxy autre que celui fourni, sauf si ce proxy écraseX-VRP-Client. Derrière Coolify ou un autre proxy existant, gardez le serveuredgefourni devant l’API : il prend l’adresse du visiteur dans l’en-têteX-Forwarded-Fordu proxy, et d’autres conteneurs de ce réseau partagé pourraient définir cet en-tête.- Les sauvegardes sont chiffrées avant de quitter la machine et une restauration a été essayée. Consultez Sauvegarde et restauration.
GEOCODER_URLest vide ou désigne le géocodeur propre à l’installation ; la surcouche de géocodage le place sur un réseau interne, sans port publié ni journal des requêtes. Un administrateur n’active le service public de l’IGN, dans Paramètres → Recherche d’adresses, qu’avec l’accord du propriétaire des données de livraison.
Connexion, sessions et mots de passe
- Les mots de passe comptent de 15 à 128 caractères et sont conservés sous forme d’empreintes Argon2id. Il n’existe ni mot de passe par défaut, ni inscription publique, ni service d’e-mail.
- Chaque utilisateur modifie son mot de passe dans Préférences personnelles après avoir saisi le mot de passe actuel ; ses autres sessions prennent fin. Un administrateur attribue un nouveau mot de passe à un autre utilisateur de l’entreprise depuis Modifier l’utilisateur, ce qui met fin aux sessions de cet utilisateur. Un administrateur qui ne peut plus se connecter a besoin d’un autre administrateur ou de la commande opérateur
python -m app.manage_users reset-password IDENTIFIANT, exécutée depuisbackendou dans un conteneur de l’application ; elle demande le mot de passe. - Chaque connexion crée un nouveau jeton aléatoire ; la base ne conserve que son empreinte SHA-256. Le mode partagé utilise le cookie
__Host-vrp_session: Secure, HttpOnly, SameSite=Strict, Path=/, sans Domain. Le mode local utilise un cookie distinctvrp_local_session, avec les mêmes protections sauf Secure. - Une session expire après 8 heures, ou après 30 minutes sans activité. L’actualisation automatique de l’état ne compte pas comme une activité. La déconnexion met fin à la session ; une modification du nom, du rôle ou de l’état actif d’un utilisateur met fin à toutes ses sessions.
- Les écritures exigent l’Origin configurée,
X-VRP-Request: 1et leX-CSRF-Tokende la session, conservé uniquement en mémoire dans le navigateur. - Les échecs de connexion sont limités à 5 par identifiant depuis une même adresse client et à 50 par identifiant toutes adresses confondues, par période de 15 minutes ; une connexion réussie remet à zéro le compte de ce client. Les échecs de changement de mot de passe comptent dans les mêmes limites. Le proxy fourni limite aussi les requêtes de connexion à 20 par minute et par adresse, avec une rafale de 10, y compris derrière un proxy HTTPS existant. Ces limites survivent aux redémarrages ; ne les effacez pas pour contourner une attaque supposée.
Protections du navigateur et du réseau
- Le mode partagé ne sert ni
/api/docsni/api/openapi.json; utilisez le contrat publié avec cette documentation. - Le proxy envoie
Strict-Transport-Security: max-age=15552000(180 jours, pour ce seul hôte) et accepte TLS 1.2 et 1.3. Derrière un proxy HTTPS existant, c’est ce proxy qui négocie TLS et détient le certificat. - L’application envoie une Content-Security-Policy limitant les scripts à la même origine, avec
frame-ancestors 'none',X-Frame-Options: DENY,X-Content-Type-Options: nosniff,Referrer-Policy: no-referreret unePermissions-Policyqui désactive caméra, micro, géolocalisation, paiement, USB et capteurs de mouvement. - Le corps des requêtes est limité à 1 Mio. Les erreurs de validation ne répètent jamais les valeurs envoyées.
- Les conteneurs de l’application, du proxy et du routeur s’exécutent avec un système de fichiers racine en lecture seule, toutes les capacités Linux retirées et
no-new-privileges.
Secrets et rôles de la base
- Les lanceurs génèrent les secrets de
workspace.env. Les mots de passe ne sont jamais des arguments de commande : les commandes de comptes les demandent, et l’outil de sauvegarde transmet les mots de passe de la base par l’environnement du processus enfant. - Trois rôles de base séparent l’administration initiale, les migrations et le rôle d’exécution restreint de l’API et du worker. Le rôle d’exécution ne peut pas supprimer lui-même de livraisons, de véhicules, de dépôts ni de calculs. Il ne le fait qu’au travers de trois fonctions appartenant au rôle de migration, qui ne touchent qu’une entreprise :
delete_orderssupprime les livraisons choisies et refuse celles qu’utilise un calcul en attente ou en cours ;delete_depotsupprime un dépôt ou un lieu qui n’est pas le dépôt principal et qu’aucun véhicule ni aucune livraison ne nomme ;remove_examplessupprime les exemples, avec les plans et calculs des véhicules d’exemple, et refuse tant qu’un calcul est en attente ou en cours. L’isolation des entreprises et des utilisateurs repose sur les autorisations de l’application, pas sur une sécurité au niveau des lignes. MONITOR_TOKEN(au moins 32 caractères) s’envoie comme jeton Bearer. Sans lui,/api/v1/metricsrépond 404. Les métriques ne contiennent que des comptages globaux, jamais de données de livraison ou d’utilisateur.
Données conservées par une installation
La base contient les comptes (identifiant, nom affiché, empreinte du mot de passe, langue), les empreintes des jetons de session et les compteurs de connexion, les dépôts et autres lieux avec leurs adresses (un lieu peut être le domicile d’un conducteur), les véhicules, les clients enregistrés avec leurs adresses, entrées et instructions, les livraisons avec leurs adresses, instructions et coordonnées, ainsi que les calculs et les plans, qui copient ces livraisons. Les adresses réseau de connexion ne sont conservées que sous forme d’empreinte, pour les limites de connexion.
Les journaux sont bornés (fichiers de 10 Mio, trois par conteneur) et excluent corps de requête, en-têtes, paramètres d’URL et requêtes SQL. Le fournisseur du fond de carte de MAP_STYLE_URL voit la zone consultée ; noms, adresses et identifiants restent sur le serveur. Si l’opérateur définit un géocodeur propre à l’installation, la recherche d’adresses l’utilise ; celui de la surcouche de géocodage ne journalise pas les requêtes. Faire pointer GEOCODER_URL vers un service public lui enverrait chaque adresse recherchée. Sans géocodeur, un administrateur peut activer pour son entreprise le service public de l’IGN : la Géoplateforme reçoit alors le texte de chaque adresse recherchée et de chaque ligne importée sans coordonnées, avec la position du dépôt. Sans l’un ou l’autre, aucune adresse n’est recherchée.
Les plans et calculs se suppriment, et les données personnelles d’une livraison s’effacent, avec les commandes de conservation. Ces commandes ne couvrent ni les clients enregistrés ni les dépôts et lieux, qui se modifient dans l’application ; un dépôt ou lieu que rien ne nomme, autre que le dépôt principal, peut y être supprimé. Les sauvegardes conservent les copies antérieures jusqu’à leur élagage.