Aller au contenu

Face Blurring - RGPD Compliance

Overview

Le système de floutage automatique des visages anonymise les photos uploadées pour respecter le RGPD. Ce traitement est effectué de manière asynchrone après l'upload des photos.

Architecture

  • FaceBlurringService: Service de détection et floutage des visages
  • BlurFacesJob: Job asynchrone exécuté après chaque upload de photo
  • Base de données: Colonnes face_blurred et faces_count dans photos_incident

Méthodes de Détection

Le service supporte plusieurs méthodes de détection (par ordre de préférence):

1. Extension PHP facedetect (Recommandé)

# Installation sur Debian/Ubuntu
apt-get update
apt-get install -y php-pear php-dev libopencv-dev
pecl install facedetect
echo "extension=facedetect.so" > /etc/php/8.2/mods-available/facedetect.ini
phpenmod facedetect
service php8.2-fpm restart

2. Haar Cascade XML (Fallback)

Si l'extension n'est pas disponible, le service cherche les fichiers Haar Cascade OpenCV:

# Télécharger Haar Cascade
mkdir -p /srv/urbafix/resources
wget https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml \
  -O /srv/urbafix/resources/haarcascade_frontalface_default.xml

Note: Cette méthode nécessite une implémentation supplémentaire (Python/OpenCV externe ou php-opencv).

3. Mode Dégradé (No-op)

Si aucune méthode n'est disponible: - Le job s'exécute sans erreur - Les photos ne sont pas modifiées - La colonne face_blurred est mise à 0

Configuration Docker

Ajouter dans le Dockerfile:

# Installation des dépendances de détection de visages
RUN apt-get update && apt-get install -y \
    php-pear \
    php-dev \
    libopencv-dev \
    && pecl install facedetect \
    && docker-php-ext-enable facedetect \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

Migration Base de Données

Exécuter la migration pour ajouter les colonnes requises:

# Via Docker
docker-compose exec db mysql -u urbafix_user -p urbafix < database/migration_face_blurring.sql

# Ou via l'interface
docker-compose exec db bash
mysql -u urbafix_user -p urbafix < /var/www/html/database/migration_face_blurring.sql

Activation

Le floutage est activé par défaut. Pour le désactiver:

# .env
FACE_BLURRING_ENABLED=false

Fonctionnement

  1. Upload photo → submit_incident.php
  2. Insertion BDD → photos_incident avec face_blurred=0
  3. Dispatch job → BlurFacesJob via queue (sync ou async)
  4. Détection visages → FaceBlurringService
  5. Floutage → Pixellisation + Gaussian blur
  6. Remplacement fichier → Image floutée écrase l'originale
  7. Update BDD → face_blurred=1, faces_count=N

Algorithme de Floutage

Le service applique un floutage en 2 étapes pour une anonymisation efficace:

  1. Pixellisation: Réduction puis agrandissement de la zone (facteur 10)
  2. Gaussian Blur: 3 passes de flou gaussien

La zone floutée inclut une marge de 20% autour du visage détecté.

Monitoring

-- Photos traitées
SELECT face_blurred, COUNT(*) as total
FROM photos_incident
GROUP BY face_blurred;

-- Photos avec visages détectés
SELECT faces_count, COUNT(*) as total
FROM photos_incident
WHERE face_blurred = 1
GROUP BY faces_count;

-- Photos en attente de traitement
SELECT COUNT(*) as pending
FROM photos_incident
WHERE face_blurred = 0;

Logs

Le service log toutes les opérations:

# Voir les logs de floutage
docker-compose logs -f web | grep BlurFacesJob

# Exemples de logs
# BlurFacesJob: Photo 123 - 2 visage(s) flouté(s)
# BlurFacesJob: Détection de visages non disponible - photo 124 ignorée
# BlurFacesJob: Photo 125 - Aucun visage détecté

Performance

  • Détection: 200-500ms par photo (selon résolution et nombre de visages)
  • Floutage: 50-100ms par visage
  • Recommandation: Utiliser QUEUE_DRIVER=redis en production pour traitement asynchrone

EXIF et floutage — extraction préalable (v3.1, 2026-08-25)

Le floutage réencode l'image via GD (imagecreatefromjpeg/imagejpeg), ce qui supprime systématiquement les métadonnées EXIF (date de prise de vue, GPS). Toute photo passée par ce pipeline perd donc ses EXIF, qu'elle contienne un visage détecté ou non.

Solution : src/ExifHelper.php extrait date/heure + GPS depuis les octets bruts de l'image avant chiffrement et avant floutage, dans les points d'upload (api/submit_incident.php, api/add_photos.php, declare_incident.php). Le résultat est persisté en base, indépendamment du fichier :

ALTER TABLE photos_incident
    ADD COLUMN exif_taken_at DATETIME NULL AFTER encrypted,
    ADD COLUMN exif_latitude DECIMAL(10,7) NULL AFTER exif_taken_at,
    ADD COLUMN exif_longitude DECIMAL(10,7) NULL AFTER exif_latitude;
// Avant chiffrement/floutage — sur les octets bruts en mémoire
$exif = ExifHelper::extract($imageData);
$db->execute(
    "INSERT INTO photos_incident (..., exif_taken_at, exif_latitude, exif_longitude) VALUES (..., ?, ?, ?)",
    [..., $exif['taken_at'], $exif['latitude'], $exif['longitude']]
);

incident_detail.php affiche ces colonnes directement (badge date/heure/GPS sur les photos) au lieu de re-parser l'EXIF du fichier stocké — qui n'en contient plus après floutage. Voir Interface Administration.

Non couvert : les photos de réponse mairie (type='mairie', upload via incident_detail.php) et les photos d'intervention agent (api/agents/incidents/add_photo.php) n'extraient pas encore l'EXIF.

Conformité ANSSI

  • ✅ Anonymisation automatique des données biométriques
  • ✅ Pas de stockage des visages originaux (écrasement immédiat)
  • ✅ Traçabilité via colonnes BDD
  • ✅ Permissions fichiers 0644 (lecture seule pour groupe/autres)

Troubleshooting

L'extension facedetect ne se charge pas

# Vérifier l'installation
php -m | grep facedetect

# Vérifier les logs PHP
docker-compose logs web | grep facedetect

# Tester manuellement
php -r "var_dump(extension_loaded('facedetect'));"

Les visages ne sont pas détectés

  • Vérifier la résolution de l'image (min 200x200px recommandé)
  • Vérifier l'éclairage de la photo
  • Tester avec Haar Cascade si extension facedetect échoue
  • Les visages de profil peuvent ne pas être détectés (normal)

Performance dégradée

  • Activer QUEUE_DRIVER=redis pour traitement asynchrone
  • Réduire la résolution des photos avant upload (app mobile)
  • Augmenter les ressources Docker (CPU/RAM)

API Info

Endpoint pour vérifier la configuration:

// TODO: Créer /backend/api/face_blurring_info.php
require_once '../../../src/Services/FaceBlurringService.php';

$service = new FaceBlurringService();
echo json_encode($service->getInfo());

// Retourne:
// {
//   "face_detection_available": true,
//   "facedetect_extension": true,
//   "haar_cascade_path": null,
//   "gd_available": true
// }