Segurança e LGPD: checklist completo para apps B2B (evite multas de até R$ 50M)

Guia prático de compliance: criptografia, consentimento, DPO, relatório de impacto e 12 medidas técnicas obrigatórias.

LGPD não é “detalhe para depois”. É obrigatório desde 2021.

Multas aplicadas pela ANPD (2023-2025):

  • Empresa de telecom: R$ 8,9M (vazamento de dados)
  • Fintech: R$ 12,4M (uso indevido de dados)
  • E-commerce: R$ 3,2M (falta de consentimento explícito)

Penalidades LGPD (Art. 52):

  • Advertência com prazo para adequação
  • Multa simples: até 2% do faturamento (limite R$ 50M por infração)
  • Multa diária
  • Publicização da infração
  • Bloqueio ou eliminação dos dados
  • Suspensão parcial ou total do banco de dados

Este artigo mostra checklist técnico e jurídico para compliance completo.

Os 10 princípios da LGPD (Art. 6º)

  1. Finalidade: Dados coletados para propósito específico e informado
  2. Adequação: Compatível com finalidades informadas
  3. Necessidade: Mínimo necessário (não coletar “por garantia”)
  4. Livre acesso: Titular consulta dados gratuitamente
  5. Qualidade: Dados exatos, claros e atualizados
  6. Transparência: Informações claras sobre tratamento
  7. Segurança: Proteção contra acessos não autorizados
  8. Prevenção: Medidas para evitar danos
  9. Não discriminação: Sem fins ilícitos ou abusivos
  10. Responsabilização: Demonstrar conformidade (accountability)

Bases legais para tratamento de dados (Art. 7º)

Nem todo dado precisa de consentimento. Existem 10 bases legais:

// lib/lgpd/legal-basis.ts
export enum LegalBasis {
  // Base 1: Consentimento explícito
  CONSENT = "consent", // "Aceito que meus dados sejam usados para X"

  // Base 2: Cumprimento de obrigação legal
  LEGAL_OBLIGATION = "legal_obligation", // Ex: guardar nota fiscal por 5 anos

  // Base 3: Execução de contrato
  CONTRACT = "contract", // Ex: dados para entrega do produto

  // Base 4: Exercício regular de direitos
  LEGAL_CLAIMS = "legal_claims", // Ex: defesa em processo

  // Base 5: Proteção da vida
  VITAL_INTEREST = "vital_interest", // Ex: dados médicos em emergência

  // Base 6: Tutela da saúde
  HEALTH = "health", // Ex: prontuário médico

  // Base 7: Interesse legítimo
  LEGITIMATE_INTEREST = "legitimate_interest", // Ex: prevenção de fraude

  // Base 8: Proteção de crédito
  CREDIT_PROTECTION = "credit_protection", // Ex: score de crédito

  // Base 9: Execução de políticas públicas
  PUBLIC_INTEREST = "public_interest", // Ex: dados do gov

  // Base 10: Estudos por órgãos de pesquisa
  RESEARCH = "research" // Ex: pesquisas acadêmicas
}

// Modelo de dados com base legal
interface DataProcessing {
  purpose: string // "Enviar comunicações de marketing"
  legalBasis: LegalBasis // CONSENT
  dataCategories: string[] // ["email", "nome"]
  retention: string // "Até revogação do consentimento"
  consentDate?: Date // Se base = CONSENT
}

Para apps B2B, bases mais comuns:

  • Contrato: Dados para prestação do serviço (nome, email, empresa)
  • Legítimo interesse: Analytics, prevenção de fraude
  • Consentimento: Marketing, compartilhamento com terceiros

Implementação técnica de consentimento

1. Captura de consentimento explícito

// components/ConsentForm.tsx
import { useState } from 'react'

export function ConsentForm({ onSubmit }: Props) {
  const [consents, setConsents] = useState({
    necessary: true, // Sempre true, não pode desmarcar
    analytics: false,
    marketing: false,
    thirdParty: false
  })

  return (
    <form onSubmit={handleSubmit}>
      <ConsentCheckbox
        checked={consents.necessary}
        disabled
        label="Necessários"
        description="Dados essenciais para funcionamento do serviço (contrato)"
        legalBasis="contract"
      />

      <ConsentCheckbox
        checked={consents.analytics}
        onChange={(checked) => setConsents({ ...consents, analytics: checked })}
        label="Análise e melhoria"
        description="Cookies e analytics para melhorar sua experiência"
        legalBasis="legitimate_interest"
      />

      <ConsentCheckbox
        checked={consents.marketing}
        onChange={(checked) => setConsents({ ...consents, marketing: checked })}
        label="Marketing"
        description="Enviaremos newsletters e ofertas relevantes"
        legalBasis="consent"
      />

      <ConsentCheckbox
        checked={consents.thirdParty}
        onChange={(checked) => setConsents({ ...consents, thirdParty: checked })}
        label="Compartilhamento"
        description="Compartilhar dados com parceiros comerciais"
        legalBasis="consent"
      />

      <Button type="submit">Continuar</Button>
      <Link href="/privacy">Política de Privacidade completa</Link>
    </form>
  )
}

2. Registro de consentimentos (auditável)

-- Schema PostgreSQL
CREATE TABLE user_consents (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES users(id),
  purpose VARCHAR(100) NOT NULL, -- 'marketing', 'analytics', etc
  legal_basis VARCHAR(50) NOT NULL,
  granted BOOLEAN NOT NULL,
  ip_address INET NOT NULL, -- IP no momento do consentimento
  user_agent TEXT NOT NULL, -- Browser
  consent_date TIMESTAMP NOT NULL DEFAULT NOW(),
  revocation_date TIMESTAMP, -- Se revogou
  version VARCHAR(20) NOT NULL -- Versão da política de privacidade
);

-- Índices
CREATE INDEX idx_user_consents_user ON user_consents(user_id);
CREATE INDEX idx_user_consents_purpose ON user_consents(purpose, granted);
// lib/lgpd/consent.ts
export async function recordConsent({
  userId,
  purpose,
  legalBasis,
  granted,
  ipAddress,
  userAgent
}: ConsentData) {
  const currentPolicyVersion = await getCurrentPolicyVersion()

  await prisma.userConsent.create({
    data: {
      userId,
      purpose,
      legalBasis,
      granted,
      ipAddress,
      userAgent,
      version: currentPolicyVersion,
      consentDate: new Date()
    }
  })

  // Log para auditoria
  await auditLog.record({
    action: 'CONSENT_RECORDED',
    userId,
    details: { purpose, granted, legalBasis }
  })
}

// Verificar se usuário deu consentimento
export async function hasConsent(
  userId: string,
  purpose: string
): Promise<boolean> {
  const consent = await prisma.userConsent.findFirst({
    where: {
      userId,
      purpose,
      granted: true,
      revocationDate: null
    },
    orderBy: { consentDate: 'desc' }
  })

  return !!consent
}

Direitos dos titulares (Art. 18)

Todo usuário tem direito a:

  1. Confirmação e acesso: “Vocês têm meus dados?”
  2. Correção: “Meu email está errado”
  3. Anonimização/bloqueio/eliminação: “Deletem meus dados”
  4. Portabilidade: “Quero exportar meus dados”
  5. Eliminação de consentimento: “Não quero mais receber emails”
  6. Informação sobre compartilhamento: “Com quem vocês compartilham?”
  7. Informação sobre não consentimento: “O que acontece se eu não consentir?”
  8. Revogação do consentimento: “Revogo meu consentimento para X”

Implementação:

// app/api/lgpd/data-subject-request/route.ts
import { NextRequest } from 'next/server'

export async function POST(req: NextRequest) {
  const { userId, requestType } = await req.json()

  // Valida identidade (2FA, email confirmation)
  await validateIdentity(userId)

  switch (requestType) {
    case 'ACCESS':
      return await handleAccessRequest(userId)

    case 'CORRECTION':
      return await handleCorrectionRequest(userId)

    case 'DELETION':
      return await handleDeletionRequest(userId)

    case 'PORTABILITY':
      return await handlePortabilityRequest(userId)

    case 'CONSENT_REVOCATION':
      return await handleConsentRevocation(userId)

    default:
      return Response.json({ error: 'Invalid request type' }, { status: 400 })
  }
}

// Exportar todos os dados do usuário (portabilidade)
async function handlePortabilityRequest(userId: string) {
  const [user, bookings, payments, consents] = await Promise.all([
    prisma.user.findUnique({ where: { id: userId } }),
    prisma.booking.findMany({ where: { userId } }),
    prisma.payment.findMany({ where: { userId } }),
    prisma.userConsent.findMany({ where: { userId } })
  ])

  const exportData = {
    user: {
      name: user.name,
      email: user.email,
      phone: user.phone,
      createdAt: user.createdAt
    },
    bookings: bookings.map(b => ({
      service: b.service,
      date: b.date,
      status: b.status
    })),
    payments: payments.map(p => ({
      amount: p.amount,
      date: p.date,
      status: p.status
    })),
    consents: consents.map(c => ({
      purpose: c.purpose,
      granted: c.granted,
      date: c.consentDate
    }))
  }

  // Gera JSON e envia por email
  const json = JSON.stringify(exportData, null, 2)
  await sendEmail({
    to: user.email,
    subject: 'Seus dados pessoais',
    attachments: [{
      filename: 'meus-dados.json',
      content: json
    }]
  })

  // Log auditoria
  await auditLog.record({
    action: 'DATA_EXPORT',
    userId,
    timestamp: new Date()
  })

  return Response.json({ success: true })
}

// Deletar conta (direito ao esquecimento)
async function handleDeletionRequest(userId: string) {
  // Anonimizar dados em vez de deletar (preserva integridade)
  await prisma.user.update({
    where: { id: userId },
    data: {
      email: `deleted-${userId}@anonimizado.com`,
      name: 'Usuário Deletado',
      phone: null,
      cpf: null,
      deletedAt: new Date(),
      // Manter ID para integridade referencial
    }
  })

  // Revoga todos os consentimentos
  await prisma.userConsent.updateMany({
    where: { userId },
    data: { revocationDate: new Date() }
  })

  await auditLog.record({
    action: 'ACCOUNT_DELETED',
    userId,
    timestamp: new Date()
  })

  return Response.json({ success: true })
}

Segurança técnica (medidas obrigatórias)

1. Criptografia de dados sensíveis

// lib/security/encryption.ts
import crypto from 'crypto'

const ALGORITHM = 'aes-256-gcm'
const KEY = process.env.ENCRYPTION_KEY! // 32 bytes

export function encrypt(text: string): string {
  const iv = crypto.randomBytes(16)
  const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(KEY, 'hex'), iv)

  let encrypted = cipher.update(text, 'utf8', 'hex')
  encrypted += cipher.final('hex')

  const authTag = cipher.getAuthTag()

  // Retorna: iv:authTag:encrypted
  return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}`
}

export function decrypt(encryptedData: string): string {
  const [ivHex, authTagHex, encrypted] = encryptedData.split(':')

  const iv = Buffer.from(ivHex, 'hex')
  const authTag = Buffer.from(authTagHex, 'hex')

  const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(KEY, 'hex'), iv)
  decipher.setAuthTag(authTag)

  let decrypted = decipher.update(encrypted, 'hex', 'utf8')
  decrypted += decipher.final('utf8')

  return decrypted
}

// Uso em modelo Prisma
// Antes de salvar CPF
user.cpf = encrypt(cpf)

// Ao ler
const cpfDecrypted = decrypt(user.cpf)

2. Hashing de senhas (bcrypt, não MD5/SHA1)

// lib/security/password.ts
import bcrypt from 'bcryptjs'

const SALT_ROUNDS = 12 // Custo computacional

export async function hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, SALT_ROUNDS)
}

export async function verifyPassword(
  password: string,
  hash: string
): Promise<boolean> {
  return bcrypt.compare(password, hash)
}

3. HTTPS obrigatório (TLS 1.2+)

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=63072000; includeSubDomains; preload'
          }
        ]
      }
    ]
  }
}

4. Proteção contra SQL Injection (ORM + prepared statements)

// ❌ ERRADO (vulnerável a SQL injection)
const query = `SELECT * FROM users WHERE email = '${userInput}'`
await db.query(query)

// ✅ CORRETO (prepared statement via Prisma)
const user = await prisma.user.findFirst({
  where: { email: userInput }
})

5. Rate limiting (prevenir brute force)

// middleware/rate-limit.ts
import rateLimit from 'express-rate-limit'

export const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutos
  max: 5, // Máximo 5 tentativas
  message: 'Muitas tentativas de login. Tente novamente em 15 minutos.',
  standardHeaders: true,
  legacyHeaders: false,
})

// Uso
app.post('/api/auth/login', loginLimiter, handleLogin)

6. CORS configurado corretamente

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/api/:path*',
        headers: [
          { key: 'Access-Control-Allow-Origin', value: 'https://seudominio.com' },
          { key: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,DELETE' },
          { key: 'Access-Control-Allow-Headers', value: 'Content-Type, Authorization' }
        ]
      }
    ]
  }
}

Relatório de Impacto à Proteção de Dados (RIPD)

Obrigatório quando:

  • Tratamento de dados sensíveis (saúde, biometria, genéticos)
  • Decisões automatizadas (perfis, scoring)
  • Alto volume de dados pessoais
  • Alto risco aos direitos dos titulares

Template RIPD:

# Relatório de Impacto à Proteção de Dados Pessoais

## 1. Identificação do Controlador
- Razão Social: [Nome da Empresa]
- CNPJ: XX.XXX.XXX/0001-XX
- DPO: [Nome] - [Email]

## 2. Descrição do Tratamento
- Finalidade: Conectar pacientes a fisioterapeutas
- Base legal: Consentimento (marketing) + Contrato (prestação de serviço)
- Dados tratados:
  - Identificação: Nome, CPF, email, telefone
  - Saúde: Histórico de lesões, laudos médicos (PDF)
  - Localização: Endereço para atendimento domiciliar
- Volume: ~5.000 pacientes/mês

## 3. Análise de Riscos

| Risco | Probabilidade | Impacto | Mitigação |
|-------|---------------|---------|-----------|
| Vazamento de dados de saúde | Média | Alto | Criptografia AES-256, acesso restrito |
| Uso indevido para marketing | Baixa | Médio | Consentimento explícito, opt-out fácil |
| Acesso não autorizado | Média | Alto | 2FA, logs de auditoria |

## 4. Medidas de Segurança
- ✅ Criptografia TLS 1.3 (transporte)
- ✅ Criptografia AES-256 (dados em repouso)
- ✅ Backups diários (retenção 30 dias)
- ✅ Acesso baseado em função (RBAC)
- ✅ Logs de auditoria (quem acessou o quê)
- ✅ Teste de penetração anual

## 5. Necessidade e Proporcionalidade
- Dados coletados: Apenas essenciais para prestação do serviço
- Retenção: Até exclusão da conta ou 5 anos (prazo legal)
- Compartilhamento: Apenas com fisioterapeuta designado

## 6. Direitos dos Titulares
- Portal de autoatendimento para exercício de direitos
- Prazo de resposta: 15 dias
- Gratuito

## 7. Conclusão
Riscos identificados e mitigados adequadamente.
Tratamento está em conformidade com LGPD.

Data: 2026-11-02
Responsável: [Nome do DPO]

Indicação de DPO (Data Protection Officer)

Quando é obrigatório:

  • Controladores de grande porte
  • Tratamento de dados sensíveis em larga escala
  • Atividade principal seja tratamento de dados

Para SMEs: DPO pode ser terceirizado (R$ 2-5K/mês).

Responsabilidades do DPO:

  • Orientar funcionários sobre LGPD
  • Atender requisições de titulares
  • Interagir com ANPD
  • Monitorar conformidade
// Contato do DPO visível no site
export function DPOContact() {
  return (
    <section>
      <h2>Encarregado de Dados (DPO)</h2>
      <p>Para exercer seus direitos ou esclarecer dúvidas sobre tratamento de dados:</p>
      <ul>
        <li>Nome: Maria Silva</li>
        <li>Email: dpo@suaempresa.com.br</li>
        <li>Telefone: (11) 1234-5678</li>
      </ul>
    </section>
  )
}

Checklist de compliance LGPD

Antes de lançar:

  • Política de Privacidade publicada e acessível
  • Termos de Uso com cláusulas de tratamento de dados
  • Captura de consentimento explícito (quando necessário)
  • DPO indicado (nome e contato público)
  • Dados sensíveis criptografados (AES-256)
  • HTTPS obrigatório (TLS 1.2+)
  • Senhas com bcrypt (12+ rounds)
  • SQL injection prevenido (ORM/prepared statements)
  • CORS configurado
  • Rate limiting em endpoints sensíveis
  • Logs de auditoria (acessos, modificações)
  • Backup automático (retenção 30 dias)

Operacional:

  • Fluxo para requisições de titulares (acesso, correção, exclusão)
  • Prazo de resposta definido (menor que 15 dias)
  • RIPD elaborado (se aplicável)
  • Contratos com operadores (DPA - Data Processing Agreement)
  • Treinamento de equipe (anual)
  • Revisão de políticas (anual ou quando houver mudanças)

Incidentes:

  • Plano de resposta a incidentes
  • Comunicação à ANPD em menor que 72h (se vazamento)
  • Comunicação aos titulares (se risco relevante)

Custos de compliance

Setup inicial:

  • Consultoria jurídica (políticas): R$ 8-15K
  • DPO terceirizado (setup): R$ 3-6K
  • RIPD (se aplicável): R$ 5-12K
  • Auditoria técnica: R$ 8-18K
  • Total inicial: R$ 24-51K

Recorrente (mensal):

  • DPO terceirizado: R$ 2-5K
  • Ferramentas (consent management): R$ 300-1.2K
  • Auditorias anuais: R$ 8-15K (diluído em 12 meses)
  • Total mensal: R$ 3-7K

ROI: Evitar 1 multa de R$ 500K+ justifica investimento.

Próximos passos

  1. Ler LGPD completa (15 páginas, Lei nº 13.709/2018)
  2. Mapear dados tratados (quais, para quê, base legal)
  3. Implementar consentimento (se necessário)
  4. Criptografar dados sensíveis (CPF, dados de saúde)
  5. Publicar Política de Privacidade
  6. Indicar DPO
  7. Treinar equipe
  8. Revisar contratos com fornecedores (AWS, Stripe, etc)

Lembre-se: LGPD não é “burocracia”. É respeito aos dados dos seus clientes. Compliance = confiança = mais conversões.

Pronto para sair do manual?

Agende o diagnóstico gratuito. Vamos mapear o gargalo, estimar o impacto e definir o primeiro resultado mensurável.

Você sai com clareza — não com um pitch de vendas.