"Segurança de banco de dados é tipo uma senha forte: você pode criar a senha mais cabulosa do mundo, mas se colar ela num post-it no monitor — não adianta nada." Então, o nosso objetivo é aprender não só a configurar os mecanismos de proteção, mas também evitar aquelas mancadas clássicas que podem jogar todo esforço fora.
1. Usar roles com permissões demais
Muita gente tem medo de limitar acesso e acaba criando roles com privilégios amplos, tipo dar SUPERUSER ou ALL PRIVILEGES. O argumento é sempre: "Vai que precisa um dia!". Só que roles com permissões demais viram um baita buraco na segurança.
Exemplo de permissão exagerada:
GRANT ALL PRIVILEGES ON DATABASE university TO student_role;
Nesse caso, a student_role ganha acesso total a todos os dados do banco. Mesmo que era só pra ler, agora pode deletar tabelas, mudar estrutura e até tirar acesso do admin.
Como evitar?
Crie roles só com o mínimo necessário. Isso é o famoso princípio do menor privilégio. Por exemplo, uma role só pra leitura deveria ser assim:GRANT CONNECT ON DATABASE university TO student_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO student_role;
Assim, fica claro o que a student_role pode fazer: conectar no banco e só ler os dados.
2. Falta de criptografia dos dados sensíveis
Imagina uma tabela users onde a gente guarda as senhas em texto puro:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT NOT NULL,
password TEXT NOT NULL
);
Se alguém mal-intencionado pegar acesso a essa tabela, leva as senhas de todo mundo. É tipo guardar a chave de casa embaixo do tapete.
Pra evitar isso, use criptografia de senha com pgcrypto. Por exemplo:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
INSERT INTO users (username, password)
VALUES ('johndoe', pgp_sym_encrypt('senha_segura', 'chave_criptografia'));
Pra conferir a senha, dá pra usar descriptografia:
SELECT username
FROM users
WHERE pgp_sym_decrypt(password::BYTEA, 'chave_criptografia') = 'senha_segura';
Nunca armazene informação sensível em texto aberto!
3. Ignorar SQL injection
SQL injection ainda é um dos ataques mais comuns, porque a galera insiste em montar query usando concatenação de string. Olha só:
DO $$
DECLARE
username TEXT := 'John';
query TEXT;
BEGIN
query := 'SELECT * FROM users WHERE username = ''' || username || ''';';
EXECUTE query;
END $$;
Se o atacante mandar John' OR '1'='1 no lugar do nome, vai vazar todos os dados da tabela users.
Como evitar? Use queries parametrizadas:
PREPARE user_query (TEXT) AS
SELECT * FROM users WHERE username = $1;
EXECUTE user_query('John');
Aqui, a variável entra de forma segura, sem chance de injection.
4. Configuração errada do pg_hba.conf
pg_hba.conf é o arquivo principal pra controlar acesso por IP. Se errar na configuração, pode acabar liberando geral sem querer.
Exemplo de configuração ruim:
host all all 0.0.0.0/0 trust
Essa linha deixa qualquer um conectar em qualquer banco de qualquer IP, sem senha.
Como evitar? Libere acesso só pros IPs que precisa e use autenticação md5 ou scram-sha-256:
host university student_role 192.168.1.0/24 md5
Assim, só a student_role da rede local entra, e com senha.
Depois de mudar o pg_hba.conf, não esquece de aplicar com:
pg_ctl reload
5. Uso errado do ROW LEVEL SECURITY
RLS é poderoso, mas não serve pra nada se configurar errado ou esquecer de ativar. Por exemplo, mesmo criando a policy, ela não funciona se o RLS estiver desligado:
CREATE POLICY my_policy ON users
USING (username = current_user);
-- Mas o RLS não tá ligado!
SELECT * FROM users; -- Vai mostrar todas as linhas!
Como evitar? Não esquece de ativar o RLS:
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
E sempre teste se a policy tá funcionando:
SET ROLE student_role;
SELECT * FROM users; -- Só vê as linhas permitidas pela policy.
6. Ações de administradores não controladas
Às vezes, o admin do banco tem acesso total aos dados, mesmo sem precisar. Isso aumenta o risco de vazamento se a conta do admin for comprometida.
Como evitar? Separe as roles. Pra tarefas de admin, crie uma role sem acesso aos dados:
CREATE ROLE admin_role WITH LOGIN CREATEDB CREATEROLE;
Pra acessar dados, crie outra role só com permissão de leitura:
CREATE ROLE data_analyst_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO data_analyst_role;
Depois, atribua as roles conforme a função do usuário:
GRANT admin_role TO some_user;
GRANT data_analyst_role TO another_user;
7. Log insuficiente
Se não configurar o log, você só vai saber de coisa estranha quando já for tarde demais.
Exemplo de log desativado:
-- Nada configurado no postgresql.conf
log_statement = 'none';
Como evitar? Ative pelo menos o log básico:
log_statement = 'all'
log_connections = on
log_disconnections = on
Assim, você vê todas as queries, conexões e desconexões.
Dá pra turbinar o controle usando a extensão pgAudit:
CREATE EXTENSION pgaudit;
8. Usar métodos de autenticação antigos
Usar métodos antigos tipo password não protege o suficiente.
Como evitar? Troque pra métodos mais seguros, tipo scram-sha-256:
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
E atualize as senhas dos usuários:
ALTER USER student_role WITH PASSWORD 'senha_nova_segura';
Pode parecer detalhe, mas cada um desses pontos pode virar um problemão de segurança. O lance é tratar o banco como se todo mundo tentando conectar fosse suspeito. Como dizem, "confia, mas confere". Agora você já tem as ferramentas pra configurar a segurança e evitar os erros mais comuns. Vai lá, manda ver, e deixa seus dados protegidos!
GO TO FULL VERSION