Application « Tractage »

Spécification technique, modèle de données et synthèse de sécurité
Application web interne de gestion des opérations de tractage syndical : planification, suivi et archivage des campagnes de distribution de tracts sur les sites d'entreprise, par des représentants.
Document — destiné au responsable sécurité Hébergement cible — OVH mutualisé (exposition Internet) Développement — NAS QNAP interne Statut données — partiellement fictives (voir §6)

1. Présentation générale

L'application permet aux représentants et aux administrateurs de planifier des campagnes de tractage, de suivre les demandes d'entraide entre représentants, de consulter les sites et leurs effectifs, et de gérer un référentiel (sites, établissements, tracts, types d'opération, expertises, comptes).

2. Architecture technique

ÉlémentDétail
FrameworkSymfony 7 (PHP 8.2)
Moteur de renduTwig (auto-échappement HTML activé par défaut)
ORMDoctrine — requêtes paramétrées
Hébergement cible (production)OVH — Hébergement mutualisé (Web) : Apache + PHP-FPM managés par OVH, exposé sur Internet. TLS/Let's Encrypt disponible, version PHP sélectionnable, base MySQL/MariaDB managée fournie par OVH.
Base de donnéesMariaDB (moteur MyISAM, sans clés étrangères, charset utf8mb4). ⚠️ En production OVH, l'hôte/port sont ceux fournis par OVH — la configuration de développement (127.0.0.1:3307 du NAS) ne s'applique pas.
Racine webDoit pointer sur le sous-dossier public/ uniquement (le reste du code ne doit pas être servi — voir §7).
EnvironnementAPP_ENV=prod (mode debug désactivé)
DéveloppementNAS QNAP interne (nginx + MariaDB natifs) — hors périmètre de production.
Contraintes mutualiséPas d'accès système bas niveau : ni firewall/ports personnalisés, ni configuration serveur libre. Durcissement principalement via .htaccess (Apache) et la configuration applicative. Exécution des migrations selon l'offre (SSH sur offres Pro+ / sinon SQL via phpMyAdmin OVH).
Surface front : aucun script tiers L'application n'inclut aucun script JavaScript tiers ni CDN : les bibliothèques front sont auto-hébergées (ex. Leaflet dans public/leaflet/) et les ressources externes (tuiles cartographiques) sont récupérées côté serveur. Historiquement motivé par un réseau interne sans Internet, ce choix reste un facteur de durcissement une fois l'application exposée sur Internet : il facilite la mise en place d'une politique de sécurité de contenu (CSP) stricte et réduit la surface d'attaque.

3. Modèle de données

Douze entités Doctrine. Le moteur MyISAM n'impose aucune contrainte d'intégrité référentielle au niveau base : les liens sont gérés applicativement (voir recommandations §7).

3.1 Comptes & personnes

EntitéTableChamps principaux
User
compte web
User email, password (haché), roles, displayName, blocked (bool). Implémente UserInterface.
Porteur
représentant
porteur lastName, firstName, birthDate, entity, email, password (haché), roles, blocked. Lié à un Site ; rattaché à des Établissements (porteur_perimetre). Implémente UserInterface.
PersonAssignmentperson_assignment Rattachement polymorphe d'un compte (User ou Porteur) à un objet : target_type, target_id, role (sdd, site_referent, creator), owner_type, owner_id. Permet de désigner une personne quel que soit son type de compte.

3.2 Référentiel

EntitéTableChamps principaux
SiteSite name, city, department, sizeCategory, effectif (saisi, nullable), sdd (nullable), latitude/longitude (cache géocodage).
Perimetre
Établissement
perimetre label. Indépendant des sites.
Tracttract label, filename (fichier uploadé), updatedAt, status (a_tracter / en_attente / perime).
OperationTypeoperation_typelabel.
Expertiseexpertiselabel (catalogue).
AccountExpertiseaccount_expertise owner_type (user/porteur), owner_id, expertise, level (initié/avancé/expert).
SectionPermissionsection_permission section (clé unique), role_required — pilote le contrôle d'accès dynamique (voir §5.2).

3.3 Activité

EntitéTableChamps principaux & relations
CampaignCampaign scheduledAt, createdAt, remarks, status (créée/prévue/réalisée/annulée), perimetreType (mono/multi/tout). Relations : Site, types d'opération (M:N), Établissements (campaign_perimetre), tracts (campaign_tract), participants (campaign_participant), créateur (voir §5.4).
HelpRequesthelp_request Demande d'entraide : campaign, porteur (destinataire), status (en attente/accepté/refusé), createdAt, respondedAt. Unicité applicative (campagne, représentant).

3.4 Nature des données (sensibilité)

4. Fonctionnalités principales

ModuleDescription
Tableau de bordIndicateurs (campagnes, sites couverts, sites oubliés avec filtre jours + effectif minimum), liste filtrable des opérations.
CampagnesCréation/édition : site, date, statut, types d'opération, Établissements (mono/multi/tous), tracts multiples, remarques. Participants renseignables quand la campagne est « Réalisée ».
Demande d'entraideEnvoi d'une sollicitation aux représentants d'un site (enregistrée + e-mail pré-rempli reprenant un résumé de la campagne). Réponse accepté/refusé par le représentant.
SitesConsultation publique (aux utilisateurs connectés) : effectifs, encadrement (SDD, référent), répartition par Établissement.
Carte des représentantsCarte Leaflet auto-hébergée, tuiles proxifiées par le NAS.
Mon espaceProfil, changement de mot de passe, expertises, demandes d'entraide reçues.
AdministrationCRUD sites, représentants, Établissements, types d'opération, tracts, expertises ; gestion des comptes & droits ; configuration des accès par section.

5. Sécurité

5.1 Authentification

5.2 Autorisation

5.3 Protections applicatives

5.4 Traçabilité du créateur de campagne

Comme les représentants (comptes Porteur) peuvent créer des campagnes et que le champ historique createdBy ne référence que les comptes web (User), le créateur réel est enregistré dans person_assignment (rôle creator), qui accepte les deux types de comptes. Ce rattachement est la source de vérité du verrou de saisie des participants : seul le créateur — User ou Porteur — est autorisé à les modifier.

6. Données fictives (avertissement)

Certaines données affichées sont générées, non réelles Un service applicatif (SiteInfoService) produit de façon déterministe (à partir de l'identifiant du site) des valeurs de démonstration : effectifs, répartition par Établissement, encadrement (SDD, référent) et DSCO lorsqu'aucune donnée réelle n'a été saisie. Ces valeurs sont stables d'un affichage à l'autre mais ne reflètent pas la réalité. Elles seront progressivement remplacées par les données saisies (champ effectif du site, rattachements SDD/référent réels, etc.).

Pour une évaluation de sécurité, retenir que le code est aujourd'hui en développement (jeu de données de test possible) et que la cible de production est un hébergement OVH mutualisé exposé sur Internet : le durcissement Internet du §7 doit être en place avant la mise en ligne.

7. Points d'attention & recommandations (cible : OVH mutualisé, Internet)

Priorisation dans l'hypothèse d'une exposition sur Internet. L'accès n'étant pas encore tranché, la première recommandation est de restreindre l'exposition au strict nécessaire.

SévéritéConstatRecommandation
Critique Comptes de démonstration affichés sur la page de connexion, mots de passe faibles (admin1234 / user1234) — exposés à tout Internet. Supprimer ces comptes et l'affichage des identifiants avant la mise en ligne ; imposer une politique de mots de passe robustes.
Critique Interface d'administration exposée sur Internet (/admin) une fois hébergée sur OVH. Restreindre l'accès à /admin par liste blanche d'IP via .htaccess si possible, et/ou authentification renforcée (MFA) ; journaliser les accès.
Élevée Chiffrement du transport indispensable (identifiants et données personnelles). Configuration actuelle en http://. Activer le certificat Let's Encrypt fourni par OVH, forcer la redirection HTTP→HTTPS et l'en-tête HSTS.
Élevée Racine web : sur mutualisé, un mauvais paramétrage du dossier racine peut exposer le code source, .env (secrets), config/, migrations/. Pointer le domaine sur public/ uniquement ; vérifier qu'aucun fichier hors public/ n'est accessible par URL.
Élevée Absence de protection contre la force brute sur le formulaire de connexion. Activer la limitation de tentatives de connexion de Symfony (login throttling) ; envisager un délai/captcha après échecs répétés.
Moyenne Jeton CSRF de connexion : le gabarit émet le jeton, mais enable_csrf n'est pas explicitement activé sur form_login. Activer enable_csrf: true sur form_login et vérifier la validation effective.
Moyenne Absence d'en-têtes de sécurité HTTP (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS). Ajouter ces en-têtes via .htaccess (Apache) ou un abonné Symfony ; l'absence de scripts tiers permet une CSP stricte.
Moyenne Cookies de session : attributs de sécurité à confirmer. Une fois HTTPS actif : cookie de session en Secure + HttpOnly + SameSite.
Moyenne Base de données managée OVH : identifiants et accès à repointer depuis la config de développement. Utiliser des identifiants dédiés ; ne pas activer l'accès distant public à la base ; mettre à jour DATABASE_URL.
Moyenne Moteur MyISAM sans clés étrangères : pas d'intégrité référentielle ni de transactions ACID. Verrouiller les suppressions en cascade côté applicatif ; envisager InnoDB si l'intégrité devient critique.
Moyenne Validation MIME réelle des tracts uploadés à confirmer (au-delà de l'extension). Valider le type MIME côté serveur ; stocker hors racine web ou servir via contrôleur (déjà le cas) ; plafonner la taille.
Faible Secrets (APP_SECRET, identifiants base) dans .env. Protéger .env (hors racine web, non versionné) ; roter APP_SECRET en cas d'exposition.
Faible Procédure de migration/déploiement sur mutualisé (pas de SSH garanti) et sauvegardes. Définir la stratégie de migration (SSH selon l'offre, sinon SQL via phpMyAdmin) ; planifier des sauvegardes régulières de la base.
Faible Données fictives affichées comme réelles (§6) ; colonne héritée referencePorteur_id inutilisée. Baliser les valeurs estimées ; nettoyer la colonne morte après validation.

8. Synthèse

bcrypt / 13
Hachage mots de passe
2 fournisseurs
Chain provider (User + Porteur)
3 rôles
USER / ADMIN / SUPER_ADMIN
Dynamique
Accès par section configurable

Les fondations d'authentification et d'autorisation sont conformes aux pratiques Symfony (hachage fort, chain provider, contrôle d'accès à deux niveaux, blocage de compte, protection du super-admin). Le passage sur un hébergement OVH mutualisé exposé sur Internet déplace l'essentiel du risque vers l'exposition : avant toute mise en ligne, traiter en priorité la suppression des comptes de démonstration, la restriction de l'accès à /admin, l'activation de TLS/HSTS, la protection anti-force-brute et le bon paramétrage de la racine web (public/). Le durcissement système étant limité sur mutualisé, il repose sur .htaccess et la configuration applicative.

Document généré pour revue de sécurité — environnement DEV / pré-production. Contenu à valider avec l'équipe de développement.