Réponse courte
Donnez au modèle son propre compte de base de données, qui ne peut lire que les quelques tables ou vues dont il a besoin, et laissez votre code, pas le modèle, exécuter chaque requête, avec les valeurs passées en paramètres. Ainsi, même un modèle confus ou manipulé ne peut voir que ce que vous avez choisi de lui montrer et ne peut rien modifier.
Question de suivi Comment l’empêcher de modifier des données qu’il ne devrait pas toucher?
Connecter un modèle de langage à une base de données est l’une des choses les plus utiles que vous puissiez construire : le personnel peut demander en mots simples « Combien de commandes avons-nous expédiées au Québec le mois dernier? » et obtenir une réponse tirée de données en direct. C’est aussi l’une des façons les plus faciles de causer des dégâts, parce que ce que produit le modèle devient des commandes qu’un vrai système exécute.
L’approche sûre ne repose pas sur un prompt astucieux. Elle repose sur des limites que la base de données elle-même impose. Partez du principe que le modèle comprendra parfois mal une demande, et qu’un jour un document ou un message qu’il lit tentera de le piéger. Ce piège s’appelle l’injection de prompt (prompt injection) : du texte caché dans les données d’entrée qui dit au modèle de faire quelque chose que son propriétaire n’a jamais voulu. Concevez ensuite la connexion pour qu’aucune de ces erreurs ne puisse vous nuire.
Le risque a un nom : l’autonomie excessive
L’OWASP Gen AI Security Project, qui fait partie de la communauté de sécurité ouverte OWASP, place l’autonomie excessive (excessive agency) parmi les principaux risques des applications d’IA. Cela signifie qu’un système d’IA peut poser des actions nuisibles à cause d’un résultat du modèle mauvais, ambigu ou manipulé. L’OWASP en voit trois causes :
| Cause | Exemple avec une base de données | Solution |
|---|---|---|
| Trop de fonctionnalités | L’outil peut exécuter n’importe quelle requête SQL, pas seulement des consultations | N’offrir que les consultations dont la tâche a besoin |
| Trop de permissions | Le compte peut aussi insérer, mettre à jour et supprimer | Un compte en lecture seule, limité à des tables précises |
| Trop d’autonomie | Les résultats ou les changements partent sans que personne vérifie | Une personne approuve tout ce qui a un effet réel |
L’exemple de l’OWASP correspond exactement : une fonction censée seulement lire des données, qui se connecte avec un compte autorisé aussi à écrire et à supprimer. Sa recommandation est d’imposer la limite par les permissions de la base de données sur le compte qu’utilise l’IA, pas par des instructions données au modèle.
Un exemple concret : un rôle en lecture seule dans PostgreSQL
Voici une configuration pour PostgreSQL, une base de données populaire à code source ouvert. L’objectif : un assistant qui répond aux questions sur les ventes à partir d’une table orders, sans voir le nom ni le courriel des clients.
-- 1. Un compte réservé à l’outil d’IA, utilisé par rien d’autre
CREATE ROLE ai_reader LOGIN; -- définir son mot de passe à partir de votre gestionnaire de secrets
-- 2. Une vue qui n’expose que les colonnes dont l’assistant a besoin
CREATE SCHEMA reporting;
CREATE VIEW reporting.order_summary AS
SELECT order_id, order_date, region, total
FROM public.orders;
-- 3. Le plus petit ensemble de privilèges qui permet de fonctionner
GRANT CONNECT ON DATABASE shop TO ai_reader;
GRANT USAGE ON SCHEMA reporting TO ai_reader;
GRANT SELECT ON reporting.order_summary TO ai_reader;
-- 4. Des filets de sécurité pour chaque session de ce compte
ALTER ROLE ai_reader SET default_transaction_read_only = on;
ALTER ROLE ai_reader SET statement_timeout = '5s';
Pourquoi chaque partie compte. Dans PostgreSQL, une nouvelle table appartient à la personne qui l’a créée, et les autres comptes n’y ont aucun accès tant que quelqu’un ne leur accorde pas un privilège, une permission nommée comme SELECT (lire) ou UPDATE (modifier). ai_reader commence donc sans aucun accès à orders. La vue, une requête enregistrée qui ressemble à une table, montre quatre colonnes et cache les autres; le guide de l’OWASP sur l’injection SQL recommande exactement cela : accorder l’accès à une vue plutôt qu’à la table sous-jacente. USAGE sur le schéma permet au compte de trouver la vue, et SELECT lui permet de la lire. Les deux dernières lignes rendent chaque session en lecture seule par défaut et arrêtent toute requête qui dure plus de cinq secondes, pour qu’une requête qui s’emballe ne ralentisse pas la base de données pour tout le monde.
À essayer : sur une copie de test de votre base de données, créez un rôle comme ai_reader, connectez-vous avec lui et essayez UPDATE reporting.order_summary SET total = 0;. Vous devriez obtenir une erreur de permission. Essayez ensuite de lire directement public.orders, ce qui devrait échouer aussi.
Laissez votre code exécuter les requêtes
La deuxième couche se trouve dans votre application. Il existe deux conceptions courantes.
Des requêtes fixes avec paramètres. Vous écrivez le SQL, et le modèle ne fait que choisir la requête et remplir des valeurs, comme une région et un mois. Votre code passe ces valeurs séparément du texte SQL : c’est ce qu’on appelle une requête paramétrée. Le guide de l’OWASP sur l’injection SQL en fait sa première défense : la base de données traite toujours un paramètre comme une donnée, si bien qu’une entrée comme tom' or '1'='1 est recherchée comme du texte plutôt qu’exécutée comme du code.
import psycopg
def orders_by_region(region: str, month_start: str):
with psycopg.connect(AI_READER_DSN) as conn:
conn.read_only = True
with conn.cursor() as cur:
cur.execute(
"SELECT count(*), sum(total) FROM reporting.order_summary "
"WHERE region = %s AND order_date >= %s::date "
"AND order_date < (%s::date + interval '1 month')",
(region, month_start, month_start))
return cur.fetchone()
Des requêtes écrites par le modèle, avec révision. Pour les questions ouvertes, le modèle rédige une instruction SELECT. Avant de l’exécuter, votre code vérifie qu’il s’agit d’une seule instruction de lecture, l’inscrit dans les journaux et ne l’exécute que par la connexion ai_reader. La vérification est une commodité; le rôle est la vraie protection.
Comment l’empêcher de modifier des données qu’il ne devrait pas toucher?
Rendez toute modification impossible au niveau de la base de données pour le compte qu’utilise l’IA. Si le rôle ne détient que SELECT sur une vue, un UPDATE ou un DELETE échoue, peu importe ce que le modèle écrit ou ce que lui dit un message injecté. Le réglage de session en lecture seule ajoute une deuxième barrière, mais voyez-le comme un filet de sécurité plutôt que comme le verrou, puisqu’une session peut désactiver ce réglage; des privilèges absents, eux, ne peuvent pas être activés de l’intérieur de la session.
Quand l’assistant doit vraiment écrire, par exemple pour créer un billet de soutien, confiez cette tâche à un compte distinct et à un outil distinct qui ne peut insérer que dans une seule table. Préférez une fonction étroite aux entrées fixes à du SQL libre. Pour tout ce qui a un effet réel, comme des remboursements ou la suppression d’enregistrements, suivez le conseil de l’OWASP : exigez l’approbation d’une personne avant que l’action s’exécute, et imposez cette approbation dans votre propre système plutôt que de demander au modèle de la respecter.
Enfin, gardez une trace. L’OWASP note que la journalisation et les limites de débit n’empêchent pas les abus, mais qu’elles vous montrent rapidement quand quelque chose d’inattendu se produit. Consignez chaque requête qu’exécute l’IA, avec l’utilisateur qui l’a demandée et l’heure, et examinez le journal après la première semaine.
Sources
- LLM06:2025 Excessive Agency — OWASP Gen AI Security Project, 5 mai 2025
- PostgreSQL 18 Documentation: 5.8. Privileges — The PostgreSQL Global Development Group, 8 juin 2026
- SQL Injection Prevention Cheat Sheet — OWASP Cheat Sheet Series, 7 juillet 2026