Aikido

Como evitar o SELECT * na SQL: prevenir fugas de dados

Desempenho

Regra
Evitar SELECCIONAR * em SQL queries.
SELECT * em produção código produz aplicações
frágeis para esquema alterações e obscurece dados dependências.

Idiomas suportados: 45+

Introdução

Utilizar SELECT * em consultas de produção recupera todas as colunas de uma tabela, incluindo colunas que a sua aplicação não utiliza. Quando os esquemas da base de dados evoluem e são adicionadas novas colunas (incluindo dados sensíveis como palavras-passe ou PII), as consultas que utilizam SELECT * começar automaticamente a recuperá-los sem alterações de código. Isto cria vulnerabilidades de segurança e quebra os pressupostos da lógica da aplicação.

Porque é importante

Impacto no desempenho: A recuperação de colunas desnecessárias aumenta o tempo de execução da consulta, o tamanho da transferência de rede e o consumo de memória. Uma tabela com 50 colunas, mas que apenas necessita de 5, significa que está a transferir 10 vezes mais dados do que o necessário, degradando os tempos de resposta e aumentando os custos de infraestrutura.

Implicações para a segurança: As novas colunas adicionadas às tabelas (campos de auditoria, sinalizadores internos, dados sensíveis do utilizador) são automaticamente expostas através de SELECT * consultas. A sua API pode começar a vazar hashes de senhas, SSNs ou dados comerciais internos que nunca foram destinados a esse ponto de extremidade.

Manutenção do código: Quando SELECT * as consultas são interrompidas após alterações do esquema, a falha ocorre em tempo de execução e não em tempo de compilação. Uma nova coluna não anulável ou um campo renomeado causa erros de produção. As listas de colunas explícitas tornam as dependências claras e quebram as compilações quando os esquemas mudam de forma incompatível.

Exemplos de código

Não 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
    };
}

Porque é que está errado: Isto recupera todas as colunas, incluindo campos potencialmente sensíveis como password_hash, ssn, internal_notes ou deleted_at. À medida que o esquema cresce, esta consulta torna-se mais lenta e expõe mais dados, mas a aplicação só utiliza três campos.

Conformidade:

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

Conclusão

Especifique sempre listas de colunas explícitas em consultas SQL. Isto evita fugas de dados, melhora o desempenho e torna claras as dependências entre o código e o esquema. O pequeno custo inicial de digitar nomes de colunas evita classes inteiras de problemas de segurança e desempenho.

FAQs

Tem perguntas?

Quando é que o SELECT * é aceitável?

Apenas em consultas ad-hoc durante o desenvolvimento ou a depuração, nunca em código de produção. Para scripts de migração de dados ou relatórios pontuais em que precisa efetivamente de todas as colunas, SELECT * é razoável. Para código de aplicação, utilize sempre listas de colunas explícitas, mesmo que necessite atualmente de todas as colunas, porque as alterações de esquema são inevitáveis.

E os ORMs que geram consultas 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.

O SELECT * tem um impacto significativo no desempenho da base de dados?

Sim, especialmente com tabelas de grande dimensão. As bases de dados têm de ler mais páginas do disco, os índices não podem ser utilizados de forma tão eficaz e os conjuntos de resultados das consultas consomem mais memória no conjunto de buffers da base de dados. O tempo de transferência da rede aumenta proporcionalmente ao tamanho dos dados. Para tabelas com colunas TEXT ou BLOB, o impacto pode ser grave.

Como é que lido com as consultas em que preciso da maioria das colunas?

Liste-as explicitamente. Utilize o preenchimento automático do seu IDE ou consulte o information_schema para gerar a lista de colunas. Algumas equipas criam objectos de vista ou utilizam vistas da base de dados que definem as colunas exactas necessárias para cada caso de utilização. A clareza e a segurança das listas explícitas superam o pequeno inconveniente.

Como é que detecto SELECT * na minha base de código?

Procure o padrão SELECT * (sem distinção entre maiúsculas e minúsculas) na sua base de código. Muitas ferramentas de análise estática e analisadores de consultas de bases de dados podem assinalar estes padrões. Durante a revisão do código, rejeite qualquer PR que contenha SELECT * no código da aplicação. Algumas equipas utilizam ganchos de pré-compromisso ou verificações de CI para detetar e bloquear automaticamente estes padrões.

Obter segurança gratuitamente

Proteja seu código, nuvem e tempo de execução em um sistema central.
Encontre e corrija vulnerabilidades rapidamente de forma automática.

Não é necessário cartão de crédito | Resultados do scan em 32secs.