Aller au contenu principal

Confidentialité des données et RGPD

Mis à jour le 29 juillet 2026

Confidentialité des données et RGPD

En tant que développeur européen, vous devez comprendre comment les données transitent via l’API OpenAI et quelles mesures prendre pour respecter le RGPD. Cette leçon couvre les aspects techniques de la conformité. Elle ne remplace pas l’avis de votre délégué à la protection des données, mais elle vous donne les gestes de code qui rendront son travail possible — et qui, faute d’avoir été posés dès la conception, coûtent très cher à rattraper.

Comment OpenAI traite vos données

Via l’API (pas ChatGPT)

La distinction avec l’usage grand public est le point de départ de toute discussion sur le sujet. Quand vous utilisez l’API OpenAI pour votre application, les données ne sont pas utilisées pour entraîner les modèles : c’est la politique API, différente de celle de ChatGPT, et c’est l’argument que vous opposerez à l’objection la plus courante en comité de sécurité. Les données sont en revanche conservées 30 jours pour permettre la détection des abus, puis supprimées. Cette rétention peut être raccourcie : vous pouvez demander la suppression anticipée via le dispositif Zero Data Retention. Reste un point à documenter dans votre analyse d’impact — les données transitent par les serveurs OpenAI, principalement situés aux États-Unis, ce qui constitue un transfert hors Union européenne.

# Vérifier la politique de rétention de votre organisation
# sur platform.openai.com/settings/organization/data-controls

Minimisation des données

Le RGPD impose de ne traiter que les données strictement nécessaires. Appliquez ce principe à vos appels API : dans l’immense majorité des cas, le modèle n’a aucun besoin de connaître le nom, l’adresse électronique ou le numéro de téléphone de la personne pour résumer sa demande ou en classer l’objet.

La technique du pseudonymat réversible répond exactement à ce besoin. Avant l’envoi, chaque donnée personnelle est remplacée par un marqueur numéroté et la correspondance est conservée en mémoire, côté serveur. L’API ne voit que [EMAIL_1] et [TEL_1]. Au retour, les marqueurs sont restaurés dans le texte produit, et l’utilisateur final récupère une réponse complète sans que les coordonnées aient jamais quitté votre système.

import re

def anonymiser_avant_envoi(texte: str) -> tuple[str, dict]:
    """Anonymise les données personnelles avant l'envoi à l'API."""
    remplacements = {}
    compteur = {"email": 0, "telephone": 0, "nom": 0}

    # Emails
    def remplacer_email(match):
        compteur["email"] += 1
        cle = f"[EMAIL_{compteur['email']}]"
        remplacements[cle] = match.group()
        return cle

    texte = re.sub(
        r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
        remplacer_email, texte
    )

    # Téléphones français
    def remplacer_tel(match):
        compteur["telephone"] += 1
        cle = f"[TEL_{compteur['telephone']}]"
        remplacements[cle] = match.group()
        return cle

    texte = re.sub(
        r'\b(?:0|\+33)\s*[1-9](?:[\s.-]*\d{2}){4}\b',
        remplacer_tel, texte
    )

    return texte, remplacements

def restaurer_donnees(texte: str, remplacements: dict) -> str:
    """Restaure les données après traitement par l'API."""
    for cle, valeur in remplacements.items():
        texte = texte.replace(cle, valeur)
    return texte

# Utilisation
from openai import OpenAI
client = OpenAI()

texte_original = "Contactez Jean Dupont a [email protected] ou 06 12 34 56 78"

# Anonymiser
texte_anonyme, mapping = anonymiser_avant_envoi(texte_original)
print(f"Envoyé a l'API : {texte_anonyme}")
# Envoyé a l'API : Contactez Jean Dupont a [EMAIL_1] ou [TEL_1]

# Appel API avec données anonymisées
response = client.responses.create(
    model="gpt-5.6-terra",
    input=f"Résumez ce message : {texte_anonyme}"
)

# Restaurer
resultat = restaurer_donnees(response.output_text, mapping)
print(f"Résultat final : {resultat}")

Regardez attentivement la sortie de cet exemple : « Jean Dupont » est toujours là. Le compteur prévoit une entrée nom, mais aucune expression régulière ne la remplit — détecter un patronyme demande une reconnaissance d’entités nommées, pas un motif de caractères. Considérez donc cette fonction comme une base à compléter, pas comme une anonymisation complète.

Pipeline conforme RGPD

La minimisation seule ne suffit pas : le règlement exige aussi que chaque traitement repose sur une base légale identifiée et soit consigné. Ce pipeline mêle les deux exigences en quatre temps — consigner la finalité et la base légale, minimiser, appeler, restaurer. L’identifiant utilisateur n’est jamais stocké en clair mais haché, si bien que le registre reste exploitable pour compter les traitements sans constituer lui-même un fichier de données personnelles.

from datetime import datetime
import json
import hashlib

class RGPDCompliantPipeline:
    """Pipeline de traitement conforme au RGPD."""

    def __init__(self):
        self.client = OpenAI()
        self.log_traitements = []

    def traiter(self, texte: str, finalite: str,
                base_legale: str, user_id: str) -> str:
        """Traite un texte en respectant le RGPD."""

        # 1. Enregistrer la base légale du traitement
        traitement = {
            "timestamp": datetime.now().isoformat(),
            "user_hash": hashlib.sha256(user_id.encode()).hexdigest()[:12],
            "finalite": finalite,
            "base_legale": base_legale,  # consentement, interet_legitime, contrat
        }

        # 2. Minimiser les données
        texte_anonyme, mapping = anonymiser_avant_envoi(texte)

        # 3. Appel API
        response = self.client.responses.create(
            model="gpt-5.6-terra",
            input=texte_anonyme,
            # Stocker le moins longtemps possible
        )

        traitement["tokens_utilises"] = response.usage.total_tokens
        self.log_traitements.append(traitement)

        # 4. Restaurer et retourner
        return restaurer_donnees(response.output_text, mapping)

    def exporter_registre(self) -> str:
        """Exporte le registre des traitements (Article 30 RGPD)."""
        return json.dumps(self.log_traitements, indent=2, ensure_ascii=False)

# Utilisation
pipeline = RGPDCompliantPipeline()

resultat = pipeline.traiter(
    texte="Le client Pierre Martin souhaite résilier son abonnement.",
    finalite="Traitement de demande de résiliation",
    base_legale="contrat",
    user_id="user-456"
)
print(resultat)
print(pipeline.exporter_registre())

Le paramètre base_legale mérite qu’on s’y arrête : traiter une demande de résiliation relève de l’exécution du contrat, pas du consentement. Choisir la mauvaise base légale est l’erreur la plus fréquente et la plus lourde de conséquences, puisqu’elle détermine les droits que l’utilisateur peut exercer sur ce traitement.

Gestion du consentement

Quand la base légale retenue est bien le consentement, celui-ci doit être recueilli, daté, versionné et surtout révocable. Le gestionnaire ci-dessous stocke le consentement par finalité — accepter l’assistance IA n’emporte pas acceptation de l’analyse de texte — et vérifie cette correspondance avant chaque traitement. La méthode de retrait porte un commentaire déterminant : supprimer la trace du consentement ne suffit pas, il faut aussi supprimer les données qui en dépendaient.

class ConsentManager:
    """Gestion du consentement utilisateur pour le traitement IA."""

    def __init__(self):
        self.consentements: dict[str, dict] = {}

    def enregistrer_consentement(self, user_id: str, finalites: list[str]):
        """Enregistre le consentement d'un utilisateur."""
        self.consentements[user_id] = {
            "finalites": finalites,
            "date": datetime.now().isoformat(),
            "version": "v1.0"
        }

    def verifier_consentement(self, user_id: str, finalite: str) -> bool:
        """Vérifie si l'utilisateur a consenti a une finalité."""
        consent = self.consentements.get(user_id)
        if not consent:
            return False
        return finalite in consent["finalites"]

    def retirer_consentement(self, user_id: str):
        """Retire le consentement (droit de retrait)."""
        if user_id in self.consentements:
            del self.consentements[user_id]
            # Ici : supprimer aussi les données associées

# Utilisation
consent = ConsentManager()

# L'utilisateur consent au traitement IA
consent.enregistrer_consentement("user-123", ["assistance_ia", "analyse_texte"])

# Vérifier avant chaque traitement
if consent.verifier_consentement("user-123", "assistance_ia"):
    # Procéder au traitement
    response = client.responses.create(
        model="gpt-5.6-terra",
        input="Question de l'utilisateur"
    )
else:
    print("Consentement requis pour ce traitement")

Droit à l’effacement (Article 17)

Lorsqu’un utilisateur demande l’effacement de ses données, votre obligation ne se limite pas à la base applicative. Il faut balayer l’ensemble des emplacements : les données locales, les logs qui contiennent des informations personnelles — souvent oubliés —, et documenter l’opération pour pouvoir en justifier. Côté API, l’action est déjà couverte par la politique de rétention : les données envoyées disparaissent automatiquement après trente jours, ou immédiatement si Zero Data Retention est activé.

def exercer_droit_effacement(user_id: str):
    """Implémente le droit a l'effacement RGPD."""

    # 1. Supprimer les données locales
    # supprimer_donnees_utilisateur(user_id)

    # 2. Les données envoyées a l'API OpenAI sont supprimées
    # automatiquement après 30 jours (ou immédiatement
    # avec Zero Data Retention activé)

    # 3. Supprimer les logs qui contiennent des données personnelles
    # supprimer_logs_utilisateur(user_id)

    # 4. Documenter la suppression
    log = {
        "action": "droit_effacement",
        "user_hash": hashlib.sha256(user_id.encode()).hexdigest()[:12],
        "date": datetime.now().isoformat(),
        "donnees_supprimees": [
            "historique_conversations",
            "profil_utilisateur",
            "logs_activite"
        ]
    }
    print(json.dumps(log, indent=2, ensure_ascii=False))

exercer_droit_effacement("user-123")

Checklist RGPD pour les développeurs

  • Identifier la base légale de chaque traitement (consentement, contrat, etc.)
  • Minimiser les données envoyées à l’API (anonymisation)
  • Tenir un registre des traitements (Article 30)
  • Implémenter le droit d’accès et le droit à l’effacement
  • Documenter les transferts hors UE (OpenAI = serveurs US)
  • Activer Zero Data Retention si possible
  • Ne jamais loguer de données personnelles en clair

Points clés à retenir

  • L’API OpenAI ne réentraîne PAS ses modèles avec vos données
  • Anonymisez les données personnelles avant chaque appel API
  • Tenez un registre des traitements conforme à l’Article 30
  • Implémentez les droits RGPD : accès, rectification, effacement, portabilité
  • Le transfert de données hors UE nécessite des garanties (clauses contractuelles)
  • Documentez chaque décision relative à la protection des données