Repérer les données personnelles avant l’envoi
Une donnée personnelle est un fait qui permet d’identifier une personne vivante. Un nom, une adresse de courriel et un numéro de téléphone en sont.
Une application qui envoie des messages à un modèle peut en envoyer sans le vouloir. On ne protège pas ce qu’on ne trouve pas : il faut donc d’abord le repérer. Le module « Sécuriser les applications LLM » en a donné un premier aperçu ; ici, vous allez plus loin.
À la fin de cette leçon
Remarque
Je peux repérer des données personnelles dans un message avec des règles, et dire ce que ces règles ratent.
Mots clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Donnée personnelle | un fait qui désigne une personne vivante | |
| Règle | un test qu’un morceau de texte réussit ou rate | contient un arobase |
| Forme | la façon dont un genre de valeur s’écrit | 0600000123 |
| Fausse alerte | un texte signalé par la règle alors qu’il n’est pas personnel | |
| Raté | une donnée personnelle que les règles n’ont pas signalée |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Les règles trouvent ce qui a une forme
Certaines données personnelles s’écrivent toujours de la même façon. Une adresse de courriel a un arobase et un point. Un mobile français a 10 chiffres et commence par 06 ou 07.
Une règle teste une forme. Le détecteur coupe un message en mots et teste chaque mot avec chaque règle. Les valeurs trouvées sont listées dans l’ordre des mots du message.
Exemple détaillé : quatre règles
| Genre | Règle | Exemple inventé |
|---|---|---|
| courriel | Un arobase, puis un point plus loin | [email protected] |
| telephone | 10 chiffres, qui commencent par 06 ou 07 | 0600000123 |
| secu | 15 chiffres (ici un numéro qui n’existe jamais) | 099999999999999 |
| carte | 16 chiffres | 4000000000000002 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Les règles ratent des choses et se trompent
Une règle ne connaît que des formes. Un nom n’a pas de forme, donc aucune règle ne le trouve. Un numéro écrit avec des espaces devient cinq mots, et aucun ne convient.
Une fausse alerte est la faute inverse. Un numéro de commande à 16 chiffres a la forme d’une carte, donc la règle le signale. Les deux fautes sont normales. Comptez-les pour savoir jusqu’où faire confiance aux règles.
Exemple détaillé : un raté et une fausse alerte
| Partie du message | Une personne dit | Les règles disent | Résultat |
|---|---|---|---|
| Bastien Exemple | Personnel | Rien trouvé | Raté |
| 06 00 00 01 24 | Personnel | Rien trouvé | Raté |
| 4000000000000002 (un numéro de commande) | Pas personnel | Carte | Fausse alerte |
| [email protected] | Personnel | Courriel | Correct |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une erreur courante
Attention
Beaucoup pensent qu’un détecteur qui n’affiche rien prouve que le message est propre. Ce n’est pas vrai. Cela veut dire qu’aucune règle n’a convenu. Un nom ou une adresse écrite en toutes lettres n’a pas de forme. Dites « aucune forme connue trouvée », jamais « aucune donnée personnelle ».
Écrire l’assistant du modèle, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Les jetons d’une réponse, ou null si elle n’en donne pas.' 'function compter(donnees, nom) {' ' return donnees.usage && typeof donnees.usage[nom] === \"number\" ? donnees.usage[nom] : null;' '}' > model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire l’assistant du modèle, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function demander(messages, echantillon, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"statut \" + res.status);' ' const d = await res.json();' ' return { texte: d.choices[0].message.content, entree: compter(d, \"prompt_tokens\"), sortie: compter(d, \"completion_tokens\"), enregistre: false };' ' } catch (erreur) {' ' console.log(\"Échantillon enregistré : aucun modèle n’a répondu (\" + erreur.message + \").\");' ' return { texte: echantillon, entree: null, sortie: null, enregistre: true };' ' }' '}' 'module.exports = { demander };' >> model.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le détecteur, partie 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { demander } = require(\"./model\");' 'const messages = [' ' \"Merci d’écrire à [email protected] au sujet du remboursement.\",' ' \"Appelez-moi au 0600000123 après dix-sept heures.\",' ' \"Mon numéro est le 06 00 00 01 24, appelez quand vous voulez.\",' ' \"Le numéro 099999999999999 figure sur le formulaire.\",' ' \"La commande 4000000000000002 part chez Bastien Exemple.\",' '];' 'const marquees = [[\"[email protected]\"], [\"0600000123\"], [\"06 00 00 01 24\"], [\"099999999999999\"], [\"Bastien Exemple\"]];' > detecteur.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le détecteur, partie 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function nettoyer(mot) {' ' let m = mot;' ' while (m.length > 0 && \".,;:?()\".includes(m[m.length - 1])) m = m.slice(0, -1);' ' return m;' '}' 'function chiffres(m, n) {' ' return m.length === n && m.split(\"\").every(function (c) { return c >= \"0\" && c <= \"9\"; });' '}' >> detecteur.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le détecteur, partie 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function sorteDe(m) {' ' const arobase = m.indexOf(\"@\");' ' if (arobase > 0 && m.indexOf(\".\", arobase) > arobase + 1) return \"courriel\";' ' if (chiffres(m, 10) && (m.startsWith(\"06\") || m.startsWith(\"07\"))) return \"telephone\";' ' if (chiffres(m, 15)) return \"secu\";' ' if (chiffres(m, 16)) return \"carte\";' ' return \"\";' '}' >> detecteur.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le détecteur, partie 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function trouver(texte) {' ' const sortie = [];' ' texte.split(\" \").forEach(function (mot) {' ' const m = nettoyer(mot);' ' if (sorteDe(m).length > 0) sortie.push({ sorte: sorteDe(m), valeur: m });' ' });' ' return sortie;' '}' >> detecteur.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le détecteur, partie 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' messages.forEach(function (texte, i) {' ' const valeurs = trouver(texte).map(function (t) { return t.valeur; });' ' const ratees = marquees[i].filter(function (v) { return valeurs.indexOf(v) < 0; });' ' const en_trop = valeurs.filter(function (v) { return marquees[i].indexOf(v) < 0; });' ' console.log((i + 1) + \" trouvé \" + JSON.stringify(trouver(texte)) + \" raté \" + JSON.stringify(ratees) + \" fausse alerte \" + JSON.stringify(en_trop));' ' });' ' const q = \"En une courte phrase, pourquoi une règle ne peut-elle pas trouver un nom ?\";' ' const echantillon = \"Un nom n’a pas de forme fixe, donc une règle n’a rien à reconnaître.\";' ' const r = await demander([{ role: \"user\", content: q }], echantillon, 60);' ' console.log(\"le modèle dit : \" + r.texte);' '}' 'main();' >> detecteur.js"Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lancer le détecteur
docker exec -w /home/node/project agent node detecteur.jsAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Ce que le Run affiche
| Ligne | Ce qu’elle montre |
|---|---|
| 1 trouvé courriel ... raté [] fausse alerte [] | Une bonne détection |
| 3 trouvé [] raté ["06 00 00 01 24"] | Un numéro avec des espaces est raté |
| 5 trouvé carte ... raté ["Bastien Exemple"] | Un nom est raté |
| 5 ... fausse alerte ["4000000000000002"] | Un numéro de commande ressemble à une carte |
| le modèle dit : ... | Une phrase. Les mots changent à chaque exécution |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.