Aikido

Comment éviter SELECT * en SQL : prévenir les fuites de données

Performance

Règle
Éviter SELECT * en SQL dans les requêtes SQL.
SELECT * dans production code fait applications
fragiles à schéma schémas et obscurcit données dépendances.

Langues prises en charge : 45+

Introduction

Utilisation SELECT * les requêtes en production récupèrent toutes les colonnes d'une table, y compris les colonnes que votre application n'utilise pas. Lorsque les schémas de base de données évoluent et que de nouvelles colonnes sont ajoutées (y compris des données sensibles comme des mots de passe ou des PII), les requêtes utilisant SELECT * les récupérer automatiquement sans modification de code. Cela crée des vulnérabilités de sécurité et rompt les hypothèses de votre logique d'application.

Pourquoi c'est important

Impact sur les performances : La récupération de colonnes inutiles augmente le temps d'exécution des requêtes, la taille des transferts réseau et la consommation de mémoire. Une table de 50 colonnes où vous n'en avez besoin que de 5 signifie que vous transférez 10 fois plus de données que nécessaire, dégradant les temps de réponse et augmentant les coûts d'infrastructure.

Implications en matière de sécurité : Les nouvelles colonnes ajoutées aux tables (champs d'audit, indicateurs internes, données utilisateur sensibles) sont automatiquement exposées via SELECT * requêtes. Votre API pourrait commencer à divulguer des hachages de mots de passe, des SSN ou des données commerciales internes qui n'étaient jamais destinées à ce point d'accès.

Maintenabilité du code : Quand SELECT * les requêtes échouent après des modifications de schéma ; la défaillance se produit à l'exécution (runtime), et non à la compilation (compile time). Une nouvelle colonne non-nullable ou un champ renommé provoque des erreurs en production. Les listes de colonnes explicites clarifient les dépendances et interrompent les builds lorsque les schémas changent de manière incompatible.

Exemples de code

❌ Non conforme :

async function getUserProfile(userId) {
    const query = 'SELECT * FROM users WHERE id = ?';
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

Pourquoi c'est incorrect : Ceci récupère toutes les colonnes, y compris des champs potentiellement sensibles comme password_hash, ssn, internal_notes ou deleted_at. À mesure que le schéma évolue, cette requête devient plus lente et expose davantage de données, alors que l'application n'utilise que trois champs.

✅ Conforme :

async function getUserProfile(userId) {
    const query = `
        SELECT name, email, created_at
        FROM users
        WHERE id = ?
    `;
    const [user] = await db.execute(query, [userId]);

    return {
        name: user.name,
        email: user.email,
        createdAt: user.created_at
    };
}

Conclusion

Spécifiez toujours des listes de colonnes explicites dans les requêtes SQL. Cela prévient les fuites de données, améliore les performances et clarifie les dépendances entre le code et le schéma. Le faible coût initial de la saisie des noms de colonnes évite des catégories entières de problèmes de sécurité et de performance.

FAQ

Des questions ?

Quand SELECT * est-il acceptable ?

Uniquement dans les requêtes ad hoc pendant le développement ou le débogage, jamais dans le code de production. Pour les scripts de migration de données ou les rapports ponctuels où vous avez réellement besoin de toutes les colonnes, SELECT * est raisonnable. Pour le code d'application, utilisez toujours des listes de colonnes explicites même si vous avez actuellement besoin de toutes les colonnes, car les changements de schéma sont inévitables.

Qu'en est-il des ORM qui génèrent des requêtes SELECT * ?

Configure your ORM to select specific fields. Most ORMs (Sequelize, TypeORM, Prisma, SQLAlchemy) support field selection: User.findOne({ attributes: ['name', 'email'] }) or prisma.user.findUnique({ select: { name: true, email: true } }). Always use these options to control what data is retrieved.

SELECT * a-t-il un impact significatif sur les performances de la base de données ?

Oui, surtout avec les tables larges. Les bases de données doivent lire plus de pages du disque, les index ne peuvent pas être utilisés aussi efficacement, et les jeux de résultats des requêtes consomment plus de mémoire dans le pool de tampons de la base de données. Le temps de transfert réseau augmente proportionnellement à la taille des données. Pour les tables avec des colonnes TEXT ou BLOB, l'impact peut être sévère.

Comment gérer les requêtes où j'ai besoin de la plupart des colonnes ?

Listez-les explicitement. Utilisez l'auto-complétion de votre IDE ou interrogez l'information_schema pour générer la liste des colonnes. Certaines équipes créent des objets vue ou utilisent des vues de base de données qui définissent les colonnes exactes nécessaires pour chaque cas d'utilisation. La clarté et la sécurité des listes explicites l'emportent sur le léger inconvénient.

Comment détecter les SELECT * dans ma codebase ?

Recherchez le pattern SELECT * (insensible à la casse) dans votre codebase. De nombreux outils d'analyse statique et analyseurs de requêtes de base de données peuvent les signaler. Lors de la revue de code, rejetez toute PR contenant SELECT * dans le code applicatif. Certaines équipes utilisent des hooks de pré-commit ou des vérifications CI pour détecter et bloquer automatiquement ces patterns.

Sécurisez-vous maintenant.

Sécuriser votre code, votre cloud et votre runtime dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Pas de carte de crédit requise | Résultats du scan en 32 secondes.