Segurança & Compliance

Segurança por Design em SaaS: Melhores Práticas para CTOs

Como construir segurança no produto desde o início — não como camada adicional depois. Os controles que todo SaaS precisa antes de ir para produção.

Everton Tubarao··5 min de leitura

Por que segurança adicionada depois é mais cara

Segurança implementada depois do MVP tem dois problemas: é mais cara de implementar (porque precisa ser retroativa a código existente) e é menos efetiva (porque as decisões de arquitetura já foram tomadas sem considerar segurança).

Um exemplo concreto: se você não projetou o modelo de autorização desde o início com o tenant_id em toda operação sensível, adicioná-lo depois significa auditar e modificar potencialmente centenas de endpoints.

Segurança por design não significa segurança perfeita — significa que as decisões arquiteturais fundamentais não criam vulnerabilidades estruturais.


Os 6 princípios de segurança por design

1. Menor privilégio

Cada componente do sistema — usuário, serviço, chave de API, role de IAM — deve ter apenas as permissões que precisa para funcionar. Nada mais.

Prática:

  • IAM roles de ECS tasks com acesso apenas ao S3 bucket específico que precisam
  • Usuário de banco com acesso apenas às tabelas que o serviço usa (não GRANT ALL)
  • API keys com escopos limitados (read-only quando não precisa escrever)
-- Errado: um usuário com acesso a tudo
GRANT ALL ON ALL TABLES IN SCHEMA public TO app_user;

-- Certo: acesso específico por tabela
GRANT SELECT, INSERT, UPDATE ON users, subscriptions TO app_user;
GRANT SELECT ON plans TO app_user;
-- Sem acesso a audit_logs, admin_configs, etc.

2. Defense in depth (defesa em camadas)

Não dependa de um único controle de segurança. Cada camada deve ser independente.

Usuário malicioso
  → Bloqueado por: Rate limiting (Nginx/WAF)
  → Bloqueado por: Validação de input (API layer)
  → Bloqueado por: Autenticação JWT verificada
  → Bloqueado por: Autorização por tenant e role
  → Bloqueado por: Row-Level Security no PostgreSQL

Se um controle falhar, o próximo ainda protege.

3. Fail securely

Quando algo dá errado, falhe de forma segura — negue acesso em vez de permitir.

// Errado: em caso de erro, permite acesso
async function checkPermission(userId: string, resource: string): Promise<boolean> {
  try {
    return await db.query('SELECT has_permission($1, $2)', [userId, resource])
  } catch (error) {
    return true  // NUNCA faça isso
  }
}

// Certo: em caso de erro, nega acesso
async function checkPermission(userId: string, resource: string): Promise<boolean> {
  try {
    return await db.query('SELECT has_permission($1, $2)', [userId, resource])
  } catch (error) {
    logger.error('permission_check_failed', { userId, resource, error })
    return false  // Nega por padrão
  }
}

4. Validação de input em toda boundary externa

Nunca confie em dados que vêm de fora do sistema: requests HTTP, mensagens de fila, arquivos de upload, webhooks.

import { z } from 'zod'

const CreateUserSchema = z.object({
  name: z.string().min(1).max(100).trim(),
  email: z.string().email().toLowerCase(),
  role: z.enum(['admin', 'member', 'viewer']),
})

// Em todo handler de API:
const result = CreateUserSchema.safeParse(req.body)
if (!result.success) {
  return res.status(422).json({ error: result.error.issues })
}
// A partir daqui, result.data é type-safe e validado

5. Criptografia para dados sensíveis

Define o que é sensível e criptografe consistentemente:

| Dado | Tratamento | |---|---| | Senha | Hash com Argon2id (nunca MD5/SHA1) | | Token de API | Hash com SHA256 (guarde só o hash) | | Dados pessoais sensíveis | AES-256-GCM com chave gerenciada no KMS | | Dados de cartão | Tokenize via Stripe/Asaas — nunca armazene | | PII em logs | Pseudonimize antes de logar |

6. Auditabilidade

Toda ação sensível deve ser logável e rastreável:

// Eventos que precisam de audit log
const AUDIT_EVENTS = [
  'user.created', 'user.deleted', 'user.role_changed',
  'tenant.settings_changed', 'billing.plan_changed',
  'data.exported', 'api_key.created', 'api_key.revoked',
]

async function auditLog(event: string, actor: { userId: string, tenantId: string }, details: object) {
  await db.insert('audit_logs', {
    event,
    actor_user_id: actor.userId,
    tenant_id: actor.tenantId,
    details: JSON.stringify(details),
    ip_address: requestContext.ip,
    created_at: new Date(),
  })
}

Checklist de segurança pré-produção

Autenticação

  • [ ] Senhas com Argon2id (trabalho computacional ≥ 3)
  • [ ] JWT com expiração curta (15–60 minutos) + refresh token rotativo
  • [ ] Refresh tokens com rotação e detecção de reutilização
  • [ ] Rate limiting em /login, /register, /forgot-password
  • [ ] Bloqueio temporário após 10 tentativas inválidas

Autorização

  • [ ] Todo endpoint verifica autenticação E autorização
  • [ ] tenant_id verificado em toda query de dado do cliente
  • [ ] Funções admin separadas de funções de usuário
  • [ ] Row-Level Security habilitado no PostgreSQL (se aplicável)

Proteção da API

  • [ ] HTTPS em todos os ambientes (sem exceção)
  • [ ] Headers de segurança: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
  • [ ] CORS configurado com allowedOrigins explícito (sem *)
  • [ ] Rate limiting global por IP e por usuário autenticado
  • [ ] Tamanho máximo de request configurado (proteção contra payloads gigantes)

Dados

  • [ ] Inputs validados com schema (Zod, Joi ou similar)
  • [ ] Queries parametrizadas (sem concatenação de strings em SQL)
  • [ ] Uploads de arquivo: tipo MIME verificado, tamanho limitado, escaneado se necessário
  • [ ] Logs sem PII ou com pseudonimização

Dependências

  • [ ] pnpm audit / npm audit no CI — bloqueio para CVEs críticos
  • [ ] Dependabot ou Renovate configurado para PRs automáticos de atualização

Secrets

  • [ ] Nenhuma chave de API, senha ou token no código ou no .env commitado
  • [ ] Secrets em AWS Secrets Manager ou similar
  • [ ] .env.example com valores fictícios, sem valores reais

O que fazer quando encontra uma vulnerabilidade

  1. Avalie a severidade usando CVSS score
  2. Contenha: disable a funcionalidade vulnerável se necessário
  3. Não anuncie publicamente até ter o patch pronto
  4. Desenvolva e teste o patch em ambiente isolado
  5. Deploy emergencial com processo acelerado de aprovação
  6. Postmortem documentado internamente
  7. Se dados de usuários foram afetados: notifique conforme LGPD/GDPR

A Codevops faz revisões de segurança e implementa todos esses controles como parte do ciclo de desenvolvimento.

Solicitar auditoria de segurança → · SOC 2 e LGPD para SaaS → · Falar com especialista →

Precisa de ajuda com segurança & compliance?

A Codevops transforma ideias em produtos reais. Cuidamos de toda a parte técnica para que você foque no seu negócio. Respondemos em até 12 horas.

Falar com especialista →