Aikido

Come evitare SELECT * in SQL: prevenire le fughe di dati

Prestazioni

Regola
Evita SELECT * nelle query SQL.
Usare SELECT * nel codice di produzione
rende le applicazioni vulnerabili ai cambiamenti dello schema e occulta le dipendenze dei dati.

Linguaggi supportati: 45+

Introduzione

L'uso di SELECT * nelle query di produzione recupera ogni colonna da una tabella, comprese quelle che l'applicazione non utilizza. Quando gli schemi dei database evolvono e vengono aggiunte nuove colonne (inclusi dati sensibili come password o PII), le query che utilizzano SELECT * iniziano automaticamente a recuperarle senza alcuna modifica al codice. Ciò crea vulnerabilità di sicurezza e compromette le ipotesi alla base della logica dell'applicazione.

Perché è importante

Impatto sulle prestazioni: Il recupero di colonne non necessarie aumenta il tempo di esecuzione delle query, le dimensioni del trasferimento di rete e il consumo di memoria. Una tabella con 50 colonne in cui te ne servono solo 5 significa che stai trasferendo una quantità di dati 10 volte superiore al necessario, degradando i tempi di risposta e aumentando i costi di infrastruttura.

Implicazioni di sicurezza: Le nuove colonne aggiunte alle tabelle (campi di audit, flag interni, dati sensibili degli utenti) vengono esposte automaticamente tramite le query SELECT * . La tua API potrebbe iniziare a mostrare hash di password, codici fiscali o dati aziendali interni che non erano mai stati destinati a quell'endpoint.

Manutenibilità del codice: Quando le query SELECT * si interrompono a causa di modifiche allo schema, l'errore si verifica in fase di esecuzione, non di compilazione. Una nuova colonna che non ammette valori nulli o un campo rinominato provocano errori in produzione. Elenchi di colonne espliciti rendono chiare le dipendenze e interrompono le build in caso di modifiche incompatibili dello schema.

Esempi di codice

❌ 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
    };
}

Perché è sbagliato: Questo comando recupera tutte le colonne, inclusi campi potenzialmente sensibili come password_hash, ssn, internal_notes o deleted_at. Man mano che lo schema cresce, questa query diventa più lenta ed espone più dati, nonostante l'applicazione utilizzi solo tre campi.

✅ 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
    };
}

Conclusione

Specifica sempre elenchi di colonne espliciti nelle query SQL. Questo previene fughe di dati, migliora le prestazioni e rende chiare le dipendenze tra codice e schema. Il piccolo costo iniziale di digitazione dei nomi delle colonne previene intere categorie di problemi di sicurezza e prestazioni.

FAQ

Hai domande?

Quando è accettabile usare SELECT *?

Solo nelle query ad-hoc durante lo sviluppo o il debugging, mai nel codice di produzione. Per gli script di migrazione dei dati o report una tantum in cui ti servono davvero tutte le colonne, SELECT * è ragionevole. Nel codice dell'applicazione, utilizza sempre elenchi di colonne espliciti anche se al momento ti servono tutte, poiché le modifiche allo schema sono inevitabili.

E per quanto riguarda gli ORM che generano query 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 * influisce in modo significativo sulle prestazioni del database?

Sì, soprattutto con tabelle di grandi dimensioni. I database devono leggere più pagine dal disco, gli indici non possono essere sfruttati in modo efficiente e i set di risultati delle query consumano più memoria nel buffer pool del database. Il tempo di trasferimento di rete aumenta proporzionalmente alla dimensione dei dati. Per le tabelle con colonne TEXT o BLOB, l'impatto può essere grave.

Come gestisco le query in cui mi serve la maggior parte delle colonne?

Elencale in modo esplicito. Sfrutta l'autocompletamento del tuo IDE o interroga information_schema per generare l'elenco delle colonne. Alcuni team creano oggetti di visualizzazione o utilizzano viste del database che definiscono le colonne esatte necessarie per ogni caso d'uso. La chiarezza e la sicurezza degli elenchi espliciti superano il piccolo inconveniente.

Come faccio a rilevare SELECT * nella mia codebase?

Cerca il pattern SELECT * (senza distinzione tra maiuscole e minuscole) nella tua codebase. Molti strumenti di analisi statica e analizzatori di query per database possono segnalarli. Durante la code review, rifiuta qualsiasi PR che contenga SELECT * nel codice dell'applicazione. Alcuni team utilizzano pre-commit hook o controlli CI per rilevare e bloccare automaticamente questi pattern.

Metti in sicurezza ora

Metti in sicurezza il tuo codice, il cloud e il runtime in un unico sistema centralizzato.
Trova e risolvi le vulnerabilità rapidamente e automaticamente.

Nessuna carta di credito richiesta | Risultati della scansione in 32 secondi.