Segurança
A integração Pix mexe com dinheiro real. Cada camada deve ter sua linha de defesa.
Armazenamento do token
Bearer token é a única credencial da Saq. Quem tem, movimenta o saldo.
| Onde guardar | OK? |
|---|---|
| Google Secret Manager | Sim |
| AWS Secrets Manager | Sim |
| HashiCorp Vault | Sim |
| Variável de ambiente no CI | Sim |
.env em produção | Não |
| Hardcoded no código | Não |
localStorage / sessionStorage | Não |
| Front-end (Web, Mobile) | Nunca |
Nunca exponha o token no front-end. Toda chamada Saq deve passar pelo seu backend, que injeta o Authorization no servidor.
Mascaramento em logs
Configure seu logger para mascarar o header Authorization e campos sensíveis do payload (payerDocument, pixKey, etc).
import pino from 'pino';
const logger = pino({
redact: {
paths: [
'req.headers.authorization',
'res.headers.authorization',
'*.payerDocument',
'*.pixKey',
],
censor: '[REDACTED]',
},
});import logging, re
class RedactFilter(logging.Filter):
def filter(self, record):
if isinstance(record.msg, str):
record.msg = re.sub(r'Bearer\s+[A-Za-z0-9._\-]+', 'Bearer [REDACTED]', record.msg)
return True
logging.getLogger().addFilter(RedactFilter())logger, _ := zap.NewProduction()
defer logger.Sync()
logger.Info("saq call",
zap.String("url", url),
zap.String("authorization", "[REDACTED]"),
)Rotação do token
| Quando rotacionar | Ação |
|---|---|
| Alguém com acesso deixa a empresa | Imediato |
| Suspeita de vazamento (commit acidental, log público) | Imediato + auditoria |
| Rotação preventiva | Trimestral ou semestral |
| Após teste de pen-test | Imediato se foi exposto durante o teste |
Solicite a rotação ao suporte da Saq. Tenha rollover planejado (dois tokens ativos por uma janela) para não derrubar produção.
Proteção do endpoint de webhook
Aceite callbacks apenas do IP oficial da Saq. Solicite o IP atual ao suporte.
location /webhooks/saq {
allow 35.199.0.0/16;
deny all;
proxy_pass http://backend;
}Crie uma WAF rule: (http.request.uri.path eq "/webhooks/saq" and ip.src ne <IP_SAQ>) → Block.
const SAQ_IPS = (process.env.SAQ_WEBHOOK_IPS ?? '').split(',');
app.post('/webhooks/saq', (req, res, next) => {
const ip = req.ip;
if (!SAQ_IPS.includes(ip)) return res.status(403).end();
next();
});Validação DICT antes de pagar
Em saques Pix por chave, valide o titular via DICT antes de transferir. Detecta troca de banco/CPF e evita pagar para destinatário errado.
async function safeWithdraw(pixKey: string, pixType: string, expectedName: string, amount: number) {
const url = new URL('https://api.saq.processamento.com/v1/pix/key');
url.searchParams.set('key', pixKey);
const dict = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SAQ_TOKEN}`,
'Content-Type': 'application/json',
},
}).then(r => r.json());
if (dict.name?.toLowerCase().trim() !== expectedName.toLowerCase().trim()) {
throw new Error(`Titular divergente: esperado ${expectedName}, encontrado ${dict.name}`);
}
return createWithdraw({ pixKey, pixType, amount });
}Detalhes em Consulta DICT.
2FA em operações sensíveis
Considere 2FA adicional na sua aplicação (não na Saq) antes de:
- Saque acima de um limite alto.
- Cadastro/alteração de chave Pix de saque.
- Login admin com permissão de movimentar saldo.
A Saq já valida no backend, mas 2FA aplicacional reduz o blast radius de uma sessão comprometida. Detalhes em 2FA.
Princípio do menor privilégio
| Setup | Recomendação |
|---|---|
| Token único pra prod + dev | Separe: token de sandbox vs token de prod. |
| Mesmo token compartilhado entre serviços | Um token por serviço/equipe (pra auditar uso). |
| Devs com acesso ao token de prod | Só infra/SRE deveria ter, devs usam sandbox. |
Armadilhas comuns
| Armadilha | Sintoma |
|---|---|
Token em .env versionado | Vaza no primeiro git push --force errado |
Logger imprime header Authorization | Token vaza em qualquer captura de log |
| Webhook aberto para qualquer IP | Payloads forjados podem ser aceitos |
| Pagar sem DICT em saque por chave | Pode pagar destinatário errado |
| Mesmo token em sandbox e produção | Erro de ambiente vira incidente em prod |
Dinheiro e precisão
A Saq Pix API usa reais com casas decimais, não centavos. Como armazenar internamente sem perder precisão, converter na borda e respeitar os limites mínimos de cada operação.
Consulta DICT
O DICT é o banco central do Bacen que guarda todas as chaves Pix registradas no Brasil. Consultar antes de pagar valida que a chave existe, mostra o titular para confirmação e reduz pagamentos para destinatários errados.