Technique

Sécurité

Ce document décrit les mesures de sécurité en place dans l'application. Son objectif est d'être transparent sur ce qui protège les données et les transactions des utilisateurs.

Authentification et sessions

Connexion par email uniquement : Shuba n'utilise pas de nom d'utilisateur. L'adresse email, combinée au mot de passe, est l'identifiant unique. Cela simplifie la gestion des comptes et réduit les risques de confusion.

Mots de passe : Les mots de passe ne sont jamais stockés en clair dans la base de données. Django applique un algorithme de hachage (PBKDF2 avec SHA-256) qui les rend impossibles à retrouver même si la base de données était compromise. Une longueur minimale de 8 caractères est imposée.

Sessions sécurisées : Quand un utilisateur se connecte, une session est créée dans la base de données. Le cookie de session est marqué comme HttpOnly (inaccessible au JavaScript) et Secure (transmis uniquement via HTTPS en production). La session dure 7 jours, renouvelée à chaque visite.

Protection CSRF : Chaque formulaire de l'application inclut un jeton CSRF (Cross-Site Request Forgery). Ce jeton empêche un site tiers de soumettre des formulaires à la place d'un utilisateur connecté.

Contrôle d'accès

Trois niveaux de rôle plateforme : Administrateur, Vendeur, et Client. Chaque vue Django vérifie le rôle de l'utilisateur avant de répondre. Un client ne peut pas accéder au tableau de bord vendeur, même en connaissant l'URL.

Cinq niveaux de rôle dans les boutiques : Propriétaire, Administrateur, Manager, Analyste, Staff. Les droits sont vérifiés à chaque action (ajouter un produit, inviter un membre, voir les rapports).

Vendeur en attente d'approbation : Même un vendeur inscrit ne peut pas publier de produits tant qu'un administrateur Shuba ne l'a pas approuvé manuellement. Cela protège la marketplace contre les boutiques frauduleuses.

Vérification au niveau des vues : Django utilise des décorateurs sur chaque vue pour vérifier les permissions. Par exemple, @login_required bloque les visiteurs non connectés, @vendor_approved_required bloque les vendeurs non approuvés.

Sécurité des transactions financières

Séquestre systématique : Aucun paiement n'est versé directement au vendeur. Les fonds transitent par un mécanisme de séquestre interne jusqu'à confirmation de réception par l'acheteur. Cela protège contre les vendeurs malhonnêtes.

Confirmation par mot de passe : Pour libérer les fonds d'une commande, l'acheteur doit ressaisir son mot de passe. Cette étape empêche qu'une personne qui aurait accès à l'écran de l'acheteur puisse valider une réception sans son consentement explicite.

Gel automatique en cas de litige : Dès qu'un litige est ouvert, la commande passe en statut DISPUTED et les fonds sont gelés immédiatement. Ils ne peuvent être libérés que par une décision de l'équipe Shuba.

Journal comptable immuable : Chaque mouvement d'argent (collecte, séquestre, reversement, commission, remboursement) crée une entrée dans la table Transaction. Ces entrées ne sont jamais modifiées, seulement ajoutées.

Sécurité des fichiers uploadés

Validation sur deux niveaux : Avant qu'un fichier soit accepté, il est validé côté navigateur (format et taille) pour un retour rapide, puis validé une seconde fois côté serveur Django. La validation serveur vérifie les octets réels du fichier (les « magic bytes »), pas seulement son extension.

Formats bloqués : Les fichiers PDF, ZIP, EXE, scripts shell et fichiers HTML sont rejetés même s'ils portent une extension .jpg. Seuls les formats JPEG, PNG, WebP et GIF sont acceptés.

Taille limitée : 5 Mo maximum pour les photos de produits, 2 Mo pour les avatars et logos.

Stockage isolé : Les fichiers sont stockés sur Supabase Storage, séparé de l'application. L'accès en lecture est public (pour afficher les images dans l'interface), mais l'écriture et la suppression nécessitent une clé secrète de service qui n'est jamais exposée côté client.

Sécurité de l'application web

HTTPS obligatoire : En production, toute tentative de connexion en HTTP est automatiquement redirigée vers HTTPS. Les communications sont chiffrées de bout en bout.

Headers de sécurité HTTP : L'application ajoute automatiquement plusieurs en-têtes de protection :

  • Strict-Transport-Security : force le navigateur à utiliser HTTPS pendant 1 an
  • X-Content-Type-Options : empêche le navigateur de deviner le type d'un fichier
  • X-Frame-Options DENY : empêche l'application d'être chargée dans un iframe (protection contre le clickjacking)
  • Content-Security-Policy : contrôle quels scripts et ressources peuvent être chargés

Variables d'environnement : Aucune information sensible (clés API, mots de passe de base de données, clés secrètes) n'est écrite dans le code source. Tout est stocké dans des variables d'environnement lues au démarrage. Le fichier .env est explicitement exclu du dépôt Git via .gitignore.

Protection des données personnelles (RGPD)

Droit à l'effacement : Un utilisateur peut supprimer son compte depuis la page de profil. L'action anonymise immédiatement ses données personnelles : email, prénom, nom, adresse, téléphone et bio sont effacés ou remplacés par des valeurs neutres.

Ce qui est conservé : Les données de commandes et de transactions sont conservées pour respecter les obligations légales comptables (article 17.3.e du RGPD), mais elles sont dissociées de toute information personnelle identifiable.

Journalisation des suppressions : Chaque suppression de compte est enregistrée dans les journaux du serveur avec l'identifiant anonymisé et l'adresse IP, sans conserver l'email, pour permettre les audits de sécurité.

Surveillance et réponse aux incidents

Sentry : En production, toutes les erreurs inattendues (code 500) sont capturées et transmises à Sentry, un service de monitoring d'erreurs. L'équipe technique reçoit une alerte avec le contexte de l'erreur, sans données personnelles d'utilisateur.

Pages d'erreur personnalisées : En cas d'erreur, l'utilisateur voit une page Shuba propre et rassurante, pas la page technique Django qui pourrait révéler des informations sur l'infrastructure.

Point de contrôle santé : L'URL /health/ répond avec l'état du service (base de données accessible ou non). Render et UptimeRobot utilisent ce point pour détecter les pannes automatiquement.