Não faça o parsing de SQL para tornar um Query Runner Read-Only
Pare de tentar proteger seu banco de dados verificando palavras-chave em strings SQL.
Se você construir uma ferramenta para executar SQL, você desejará um modo de apenas leitura. Você quer evitar que um UPDATE acidental apague seus dados. Seu primeiro pensamento pode ser bloquear palavras como DELETE ou DROP.
Não faça isso.
Verificações de string são fáceis de burlar. Um usuário pode usar uma cláusula WITH para esconder um DELETE. Eles podem usar comentários para esconder comandos. Eles podem chamar uma função que escreve em uma tabela. Você acaba em um jogo perdido de whack-a-mole.
Deixe o banco de dados lidar com a segurança.
O Postgres possui um recurso nativo para isso. Você pode declarar uma transação como read-only. O servidor então recusará qualquer comando de escrita. Isso abrange CTEs, funções e DDL.
Veja como implementar isso corretamente em Python:
- Use uma transação real definindo o
autocommitcomoFalse. - Execute
SET TRANSACTION READ ONLYcomo o primeiro comando. - Defina um
statement_timeoutpara evitar que consultas de longa duração bloqueiem seu sistema. - Use
rollback()ao final para liberar locks e snapshots.
Essa abordagem não inspeciona o texto SQL. A consulta vai para o servidor exatamente como foi escrita. Você está dizendo ao motor para aplicar a regra.
A segurança exige duas partes:
- Proteção contra escritas: Use transações de apenas leitura.
- Proteção contra abuso de recursos: Use timeouts e limites de linhas.
Uma consulta de apenas leitura ainda pode derrubar seu sistema com um join