No PostgreSQL:
- Role é a entidade de controle de permissões (pode representar um usuário ou um grupo).
- Uma Role pode:
- Fazer login (ser um usuário) → atributo
LOGIN - Conter outras roles (funciona como grupo)
- Ter permissões específicas (
CREATE,SUPERUSER,REPLICATIONetc.)
- Fazer login (ser um usuário) → atributo
🔹 Usuário = Role com LOGIN
🔹 Grupo = Role sem LOGIN
-- Criar um usuário com login e senha
CREATE ROLE felipe LOGIN PASSWORD 'SenhaForte!123';
-- Criar um grupo (sem login)
CREATE ROLE dev_team;
-- Criar com atributos adicionais
CREATE ROLE admin LOGIN PASSWORD 'SenhaMuitoForte!' SUPERUSER CREATEDB CREATEROLE;Atributos comuns:
LOGIN→ pode se conectarSUPERUSER→ sem restriçõesCREATEDB→ pode criar bancosCREATEROLE→ pode criar/gerenciar rolesINHERIT→ herda permissões de roles associadas (padrão)NOCREATEROLE/NOCREATEDB→ remove privilégios
-- Adicionar um usuário ao grupo
GRANT dev_team TO felipe;
-- Remover usuário do grupo
REVOKE dev_team FROM felipe;- Com
INHERIT(padrão) → permissões do grupo passam automaticamente. - Sem
INHERIT→ precisa usarSET ROLEpara assumir privilégios.
| Objeto | Privilégios Disponíveis |
|---|---|
| DATABASE | CONNECT, CREATE, TEMP |
| SCHEMA | USAGE, CREATE |
| TABLE/VIEW | SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER |
| SEQUENCE | USAGE, SELECT, UPDATE |
| FUNCTION | EXECUTE |
| TYPE | USAGE |
CREATE ROLE app_user LOGIN PASSWORD 'senha_app';
CREATE ROLE leitura;
CREATE ROLE escrita;GRANT CONNECT ON DATABASE minha_base TO app_user;
GRANT USAGE ON SCHEMA public TO leitura, escrita;GRANT SELECT ON ALL TABLES IN SCHEMA public TO leitura;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO escrita;ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO leitura;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT INSERT, UPDATE, DELETE ON TABLES TO escrita;GRANT leitura TO app_user;
GRANT escrita TO app_user;REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM leitura;
REVOKE escrita FROM app_user;\du -- Listar roles existentes
\z tabela_exemplo -- Mostrar privilégios de tabelas
SELECT rolname, rolcanlogin, rolsuper FROM pg_roles; -- Checar membros- Nunca usar
SUPERUSERsem necessidade. - Separar roles de conexão e roles de privilégio.
- Ex.:
user_apisó tem LOGIN e pertence arole_leitura.
- Ex.:
- Usar grupos para gerenciar permissões em vez de conceder direto a cada usuário.
- Alterar permissões padrão (
ALTER DEFAULT PRIVILEGES) para evitar esquecer de novos objetos. - Revisar permissões periodicamente (
\du,\z).
CREATE ROLE app_read;
CREATE ROLE app_write;
CREATE ROLE app_prod LOGIN PASSWORD 'SenhaSegura!';
GRANT USAGE ON SCHEMA public TO app_read, app_write;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_read;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_write;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO app_read;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT INSERT, UPDATE, DELETE ON TABLES TO app_write;
GRANT app_read, app_write TO app_prod;Integrar todos os conceitos de segurança aprendidos para criar um banco e serviço API seguros, aplicando autenticação, criptografia, auditoria e testes de vulnerabilidades.
No Linux:
sudo apt update && sudo apt install postgresql postgresql-contrib
sudo service postgresql startNo Windows/Mac: instalar via PostgreSQL Installer ou Docker:
docker run --name postgres-seguro -e POSTGRES_PASSWORD=admin123 -p 5432:5432 -d postgres:15-- Criar usuário de aplicação com senha forte
CREATE ROLE app_user LOGIN PASSWORD 'SenhaForte!@123';
-- Criar banco de dados
CREATE DATABASE empresa_segura OWNER app_user;
-- Restringir permissões
REVOKE ALL ON DATABASE empresa_segura FROM PUBLIC;
GRANT CONNECT ON DATABASE empresa_segura TO app_user;\c empresa_segura
-- Criar schema
CREATE SCHEMA sistema AUTHORIZATION app_user;
-- Tabela de usuários
CREATE TABLE sistema.usuarios (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
senha_hash TEXT NOT NULL, -- senha armazenada como hash
criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tabela de registros de acesso
CREATE TABLE sistema.logs_acesso (
id SERIAL PRIMARY KEY,
usuario_id INT REFERENCES sistema.usuarios(id),
ip_origem VARCHAR(45),
data_hora TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
acao TEXT
);CREATE EXTENSION IF NOT EXISTS pgcrypto;
INSERT INTO sistema.usuarios (nome, email, senha_hash)
VALUES (
'Admin',
'[email protected]',
crypt('SenhaUltraSegura123!', gen_salt('bf'))
);import express from "express";
import pkg from "pg";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
const { Pool } = pkg;
const pool = new Pool({
user: "app_user",
host: "localhost",
database: "empresa_segura",
password: "SenhaForte!@123",
port: 5432,
ssl: false // Em produção, usar SSL!
});
const app = express();
app.use(express.json());
app.post("/login", async (req, res) => {
const { email, senha } = req.body;
const { rows } = await pool.query("SELECT * FROM sistema.usuarios WHERE email=$1", [email]);
if (rows.length === 0) return res.status(401).json({ erro: "Credenciais inválidas" });
const usuario = rows[0];
const senhaValida = await bcrypt.compare(senha, usuario.senha_hash);
if (!senhaValida) return res.status(401).json({ erro: "Credenciais inválidas" });
const token = jwt.sign({ id: usuario.id }, "segredo", { expiresIn: "1h" });
res.json({ token });
});
app.listen(3000, () => console.log("API Segura rodando na porta 3000"));Boas práticas aplicadas:
- Uso de hash (bcrypt) para senhas.
- JWT para autenticação.
- Consultas parametrizadas para evitar SQL Injection.
CREATE EXTENSION pgaudit;
ALTER SYSTEM SET pgaudit.log = 'read, write';
SELECT pg_reload_conf();sqlmap -u "http://localhost:3000/login" --data="[email protected]&senha=123" --batch- Abrir OWASP ZAP.
- Configurar como proxy do navegador.
- Navegar na API e realizar scan.
sonar-scanner -Dsonar.projectKey=api_segura -Dsonar.sources=. -Dsonar.host.url=http://localhost:9000✅ Coleta apenas dados necessários.
✅ Consentimento informado (em endpoints de cadastro).
✅ Senhas armazenadas de forma segura.
✅ Criptografia em trânsito (HTTPS).
✅ Plano de resposta a incidentes.
- Banco PostgreSQL seguro com controle de acesso.
- API protegida contra ataques comuns (SQL Injection, vazamento de dados).
- Logs e auditoria habilitados.
- Testes de vulnerabilidade realizados e corrigidos.
- Sistema em conformidade básica com LGPD/GDPR.
Criar um ambiente controlado com PostgreSQL e uma API vulnerável que permita SQL Injection.
Depois, aplicar as correções e implementar camadas de segurança para proteção contra ataques comuns.
CREATE DATABASE seguranca_teste;
\c seguranca_teste;
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
senha VARCHAR(100) NOT NULL
);
INSERT INTO usuarios (nome, email, senha)
VALUES
('Admin', '[email protected]', 'senha123'),
('João', '[email protected]', 'abc123');import express from "express";
import pkg from "pg";
const { Pool } = pkg;
const pool = new Pool({
user: "postgres",
host: "localhost",
database: "seguranca_teste",
password: "postgres",
port: 5432
});
const app = express();
app.use(express.json());
app.post("/login", async (req, res) => {
const { email, senha } = req.body;
// ❌ Consulta vulnerável
const query = `SELECT * FROM usuarios WHERE email = '${email}' AND senha = '${senha}'`;
const result = await pool.query(query);
if (result.rows.length > 0) {
res.json({ sucesso: true, usuario: result.rows[0] });
} else {
res.status(401).json({ sucesso: false });
}
});
app.listen(3000, () => console.log("API vulnerável rodando na porta 3000"));Usando SQLMap:
sqlmap -u "http://localhost:3000/login" --data="[email protected]&senha=123" --batch --level=5 --risk=3Ou manualmente via Postman:
{
"email": "[email protected]",
"senha": "' OR '1'='1"
}✅ Resultado: o sistema loga sem precisar da senha correta.
const result = await pool.query(
"SELECT * FROM usuarios WHERE email = $1 AND senha = $2",
[email, senha]
);import bcrypt from "bcrypt";
const hash = await bcrypt.hash(senha, 10);
await pool.query(
"INSERT INTO usuarios (nome, email, senha) VALUES ($1, $2, $3)",
[nome, email, hash]
);
const senhaValida = await bcrypt.compare(senhaDigitada, senhaHashBanco);import jwt from "jsonwebtoken";
const token = jwt.sign({ id: usuario.id }, "chave-secreta", { expiresIn: "1h" });No pg_hba.conf:
hostssl seguranca_teste app_user 0.0.0.0/0 md5
CREATE EXTENSION pgaudit;
ALTER SYSTEM SET pgaudit.log = 'read, write';
SELECT pg_reload_conf();sqlmap -u "http://localhost:3000/login" --data="[email protected]&senha=' OR '1'='1" --batch✅ Resultado esperado: falha do ataque (nenhum registro retornado).
- Validação e sanitização de entrada (não confiar no cliente).
- Queries parametrizadas.
- Hashing de senhas (bcrypt/Argon2).
- Controle de acesso (JWT/RBAC).
- Criptografia em trânsito (TLS/SSL).
- Auditoria e monitoramento (PgAudit).
- Backups seguros e testados.
- API segura contra SQL Injection.
- Senhas protegidas.
- Tráfego criptografado.
- Logs e auditoria ativos.
- Prática de ataque + defesa consolidada.