Pular para o conteúdo principal

Práticas de Segurança

Diretrizes abrangentes de segurança para desenvolvimento, deploy e operação do BITIO, cobrindo desde código até infraestrutura AWS.

Princípios de Segurança

1. Security by Design

  • Threat modeling em cada nova funcionalidade
  • Princípio do menor privilégio para IAM roles e usuários
  • Defense in depth - múltiplas camadas de proteção
  • Fail secure - falhar de forma segura quando algo der errado

2. Confidencialidade, Integridade, Disponibilidade (CIA)

  • Confidencialidade: Dados acessíveis apenas por quem deve
  • Integridade: Dados não podem ser alterados sem autorização
  • Disponibilidade: Serviços disponíveis quando necessário

Segurança de Dados

Classificação de Dados

ClassificaçãoExemplosProteção Requerida
PúblicoCardápios, páginas de linksControle básico de acesso
InternoMétricas, logs de sistemaAcesso restrito a funcionários
ConfidencialDados de clientes, tokens OAuthCriptografia + controle rigoroso
RestritoSenhas, chaves privadasEncryption at rest + in transit

Encryption

At Rest (Dados Armazenados)

# RDS
StorageEncrypted: true
KmsKeyId: alias/bitio-rds-key

# S3
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256

# EBS (Worker EC2)
Encrypted: true
KmsKeyId: alias/bitio-ebs-key

In Transit (Dados em Trânsito)

  • TLS 1.2+ obrigatório para todas as APIs
  • HTTPS everywhere - sem HTTP em produção
  • Certificate pinning no frontend quando necessário

Secrets Management

// ❌ Nunca hardcoded
const apiKey = "sk_live_abc123...";

// ✅ AWS Systems Manager Parameter Store
const getSecret = async (name: string): Promise<string> => {
const ssm = new SSMClient({});
const result = await ssm.send(new GetParameterCommand({
Name: `/bitio/${process.env.NODE_ENV}/${name}`,
WithDecryption: true,
}));
return result.Parameter?.Value || '';
};

Autenticação e Autorização

Multi-Tenant Security

// Sempre validar tenant_id do token
interface AuthContext {
userId: string;
tenantId: string;
role: 'owner' | 'manager' | 'admin_2biz';
}

// ❌ Nunca confiar no body da requisição
async function getProducts(tenantId: string) { // Vem do body - inseguro
return await prisma.product.findMany({
where: { tenantId } // Pode acessar dados de outro tenant
});
}

// ✅ Sempre usar o token JWT validado
async function getProducts(auth: AuthContext) {
return await prisma.product.findMany({
where: { tenantId: auth.tenantId } // Seguro - vem do JWT
});
}

Role-Based Access Control (RBAC)

// Matriz de permissões
const permissions = {
'owner': ['*'], // Acesso total ao tenant
'manager': ['read:*', 'write:menu', 'write:reservations'],
'admin_2biz': ['read:*', 'write:*', 'admin:*'], // Acesso a todos os tenants
};

function hasPermission(role: string, action: string, resource: string): boolean {
const userPermissions = permissions[role] || [];

// Verifica permissão específica ou wildcard
return userPermissions.some(perm =>
perm === `${action}:${resource}` ||
perm === `${action}:*` ||
perm === '*'
);
}

// Middleware de autorização
function requirePermission(action: string, resource: string) {
return (req: Request, res: Response, next: NextFunction) => {
const auth = req.auth; // Do JWT middleware

if (!hasPermission(auth.role, action, resource)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}

next();
};
}

// Uso em rotas
app.get('/products',
requirePermission('read', 'menu'),
getProductsHandler
);

Segurança de APIs

Input Validation

import { z } from 'zod';

// Schema de validação robusto
const createProductSchema = z.object({
name: z.string()
.min(1, 'Nome obrigatório')
.max(255, 'Nome muito longo')
.regex(/^[a-zA-Z0-9\s\-_\.]+$/, 'Caracteres inválidos'), // Sanitização

price: z.number()
.positive('Preço deve ser positivo')
.max(999999.99, 'Preço muito alto'),

description: z.string()
.max(1000, 'Descrição muito longa')
.optional()
.transform(val => val ? sanitizeHtml(val) : val), // Remove HTML malicioso

categoryId: z.string().uuid('ID de categoria inválido'),
});

// Sanitização adicional
function sanitizeHtml(input: string): string {
return input
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') // Remove scripts
.replace(/[<>]/g, '') // Remove brackets
.trim();
}

Rate Limiting

// Rate limiting por tenant e endpoint
import rateLimit from 'express-rate-limit';

const createRateLimiter = (windowMs: number, max: number) => rateLimit({
windowMs,
max,
keyGenerator: (req) => `${req.auth.tenantId}:${req.route.path}`,
message: { error: 'Too many requests' },
standardHeaders: true,
legacyHeaders: false,
});

// Limites diferentes por tipo de operação
app.use('/api/auth', createRateLimiter(15 * 60 * 1000, 5)); // 5 tentativas de login por 15min
app.use('/api/campaigns', createRateLimiter(60 * 60 * 1000, 10)); // 10 campanhas por hora
app.use('/api', createRateLimiter(60 * 1000, 100)); // 100 requests por minuto (geral)

SQL Injection Prevention

// ✅ Prisma ORM - Safe by default
const products = await prisma.product.findMany({
where: {
tenantId: auth.tenantId,
name: { contains: searchTerm }, // Prisma escapa automaticamente
},
});

// ✅ Se usar query raw, usar parametrização
const result = await prisma.$queryRaw`
SELECT * FROM products
WHERE tenant_id = ${auth.tenantId}
AND name ILIKE ${`%${searchTerm}%`}
`;

// ❌ Nunca concatenar strings diretamente
const query = `SELECT * FROM products WHERE name = '${searchTerm}'`; // PERIGOSO!

Segurança de Infraestrutura

Network Security

# VPC Configuration
VPC:
CidrBlock: 10.0.0.0/16

SubnetPrivate:
CidrBlock: 10.0.1.0/24 # RDS, Worker interno

SubnetPublic:
CidrBlock: 10.0.2.0/24 # Load Balancer, NAT

# Security Groups (Firewall Rules)
DatabaseSG:
GroupDescription: "RDS access"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 5432
ToPort: 5432
SourceSecurityGroupId: !Ref WorkerSG # Só o Worker pode acessar

WorkerSG:
GroupDescription: "Worker EC2 access"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0 # SSH via SSM, não direto
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSG

IAM Best Practices

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LeastPrivilegeExample",
"Effect": "Allow",
"Action": [
"rds:DescribeDBInstances"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "sa-east-1"
}
}
},
{
"Sid": "ResourceSpecific",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::bitio-assets-${aws:PrincipalTag/Environment}/*"
},
{
"Sid": "DenyDangerousActions",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser",
"rds:DeleteDBInstance"
],
"Resource": "*"
}
]
}

Secrets Rotation

// Rotação automática de tokens OAuth
export class TokenRotationService {
async rotateMetaToken(tenantId: string): Promise<void> {
try {
// 1. Obter novo token usando refresh token
const newToken = await this.refreshMetaToken(tenantId);

// 2. Testar novo token
await this.validateToken(newToken);

// 3. Atualizar no Parameter Store
await this.updateTokenInSSM(tenantId, newToken);

// 4. Invalidar cache
await this.invalidateTokenCache(tenantId);

logger.info('Token rotated successfully', { tenantId });
} catch (error) {
// 5. Alertar se falhar
await this.alertTokenRotationFailure(tenantId, error);
throw error;
}
}

// Executar rotação semanalmente
@Cron('0 2 * * 0') // Domingo 2h
async rotateAllTokens(): Promise<void> {
const integrations = await prisma.integration.findMany({
where: { type: 'meta_ads', status: 'active' }
});

for (const integration of integrations) {
await this.rotateMetaToken(integration.tenantId);
await new Promise(resolve => setTimeout(resolve, 1000)); // Rate limit
}
}
}

Segurança de Código

Dependency Management

// package.json - Versões fixas/ranges seguros
{
"dependencies": {
"express": "4.18.2", // Versão fixa para prod
"prisma": "^5.1.0", // Range seguro (patch updates)
"@aws-sdk/client-s3": "~3.400.0" // Minor updates apenas
}
}
# Auditoria regular de dependências
npm audit --audit-level high
npm audit fix

# Verificar vulnerabilidades conhecidas
npx snyk test
npx retire --js

Static Analysis Security Testing (SAST)

# .gitlab-ci.yml
security:sast:
stage: security
image: securecodewarrior/gitlab-sast:latest
script:
- semgrep --config=auto --json --output=sast-report.json src/
- eslint-security src/ --ext .ts,.js
artifacts:
reports:
sast: sast-report.json
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

Secure Coding Guidelines

// 1. Validação de entrada sempre
function processUserInput(input: unknown): string {
if (typeof input !== 'string') {
throw new ValidationError('Input must be string');
}

const sanitized = input.trim().substring(0, 1000); // Limitar tamanho

if (!/^[a-zA-Z0-9\s\-_.@]+$/.test(sanitized)) {
throw new ValidationError('Invalid characters');
}

return sanitized;
}

// 2. Evitar information disclosure
function handleError(error: Error, res: Response): void {
logger.error('Application error', {
error: error.message,
stack: error.stack,
traceId: res.locals.traceId
});

// Não vazar detalhes em produção
const message = process.env.NODE_ENV === 'production'
? 'Internal server error'
: error.message;

res.status(500).json({ error: message });
}

// 3. Timeouts para prevenir DoS
const fetchWithTimeout = async (url: string, timeout = 5000): Promise<Response> => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);

try {
const response = await fetch(url, {
signal: controller.signal,
headers: {
'User-Agent': 'BITIO/1.0',
// Não vazar informações no User-Agent
}
});
return response;
} finally {
clearTimeout(timeoutId);
}
};

Monitoramento de Segurança

Security Metrics

// Métricas de segurança a monitorar
interface SecurityMetrics {
// Authentication
failedLoginAttempts: number;
suspiciousLoginPatterns: number;

// Authorization
unauthorizedAccessAttempts: number;
privilegeEscalationAttempts: number;

// Input validation
maliciousInputDetected: number;
sqlInjectionAttempts: number;

// Infrastructure
unusualNetworkTraffic: number;
failedAWSAPICalls: number;

// Data
dataExfiltrationAlerts: number;
unusualDataAccess: number;
}

Security Alerts

// Sistema de alertas de segurança
export class SecurityAlerting {
async detectSuspiciousActivity(event: SecurityEvent): Promise<void> {
const rules = [
{
name: 'Múltiplas tentativas de login',
condition: (e) => e.type === 'login_failed' && e.count > 5,
severity: 'high',
},
{
name: 'Acesso a dados de outro tenant',
condition: (e) => e.type === 'unauthorized_access' && e.crossTenant,
severity: 'critical',
},
{
name: 'Upload de arquivo suspeito',
condition: (e) => e.type === 'file_upload' && e.malwareDetected,
severity: 'high',
},
];

for (const rule of rules) {
if (rule.condition(event)) {
await this.sendAlert({
rule: rule.name,
severity: rule.severity,
event,
timestamp: new Date(),
});
}
}
}

private async sendAlert(alert: SecurityAlert): Promise<void> {
// Slack para alertas críticos
if (alert.severity === 'critical') {
await this.notifySlack(alert);
}

// PagerDuty para alta severidade
if (['critical', 'high'].includes(alert.severity)) {
await this.notifyPagerDuty(alert);
}

// Log estruturado sempre
logger.warn('Security alert', { alert });
}
}

Incident Response

Security Incident Response Plan

  1. Detecção: Alertas automáticos + monitoramento
  2. Análise: Determinar escopo e impacto
  3. Contenção: Isolar sistemas afetados
  4. Erradicação: Remover causa raiz
  5. Recuperação: Restaurar operações normais
  6. Lições aprendidas: Post-mortem e melhorias

Playbooks por Tipo de Incidente

Data Breach Suspeita

# 1. Isolar imediatamente
aws ec2 modify-security-group-rules --group-id sg-xxx --security-group-rules '...'

# 2. Capturar evidências
aws logs create-export-task --log-group-name /aws/lambda/bitio-api

# 3. Notificar stakeholders
# 4. Investigar logs
# 5. Remediar vulnerabilidade

Token Comprometido

# 1. Revogar token imediatamente
curl -X POST "https://graph.facebook.com/oauth/revoke" -d "access_token=$TOKEN"

# 2. Rotacionar todos os secrets relacionados
aws ssm put-parameter --name "/bitio/prod/meta-token" --value "$NEW_TOKEN" --overwrite

# 3. Verificar uso não autorizado
# 4. Atualizar aplicação com novo token

Compliance e Auditoria

Auditoria de Acesso

-- Log de todas as operações por usuário/tenant
CREATE TABLE audit_logs (
id UUID PRIMARY KEY,
user_id UUID,
tenant_id UUID,
action VARCHAR(100),
resource_type VARCHAR(50),
resource_id UUID,
ip_address INET,
user_agent TEXT,
timestamp TIMESTAMP DEFAULT NOW(),
success BOOLEAN,
error_message TEXT
);

-- Consultas de auditoria
-- Acessos suspeitos (fora do horário)
SELECT * FROM audit_logs
WHERE EXTRACT(hour FROM timestamp) NOT BETWEEN 8 AND 22
AND action IN ('DELETE', 'EXPORT');

-- Tentativas de acesso cross-tenant
SELECT * FROM audit_logs a1
WHERE EXISTS (
SELECT 1 FROM audit_logs a2
WHERE a2.user_id = a1.user_id
AND a2.tenant_id != a1.tenant_id
AND a2.timestamp BETWEEN a1.timestamp - INTERVAL '1 hour'
AND a1.timestamp + INTERVAL '1 hour'
);

LGPD Compliance

// Implementação de direitos LGPD
export class DataPrivacyService {
// Direito de acesso (Art. 15)
async exportUserData(customerId: string, tenantId: string): Promise<UserDataExport> {
return {
personalData: await this.getPersonalData(customerId, tenantId),
orders: await this.getOrders(customerId, tenantId),
interactions: await this.getInteractions(customerId, tenantId),
consents: await this.getConsents(customerId, tenantId),
};
}

// Direito ao esquecimento (Art. 17)
async deleteUserData(customerId: string, tenantId: string): Promise<void> {
await prisma.$transaction(async (tx) => {
// Anonimizar em vez de deletar (manter integridade referencial)
await tx.customer.update({
where: { id: customerId, tenantId },
data: {
name: 'Usuario Anonimizado',
email: null,
phone: null,
birthDate: null,
tags: [],
},
});

// Deletar dados não essenciais
await tx.customerContact.deleteMany({
where: { customerId },
});
});

// Log da operação para auditoria
logger.info('User data deleted', { customerId, tenantId });
}
}

Este conjunto de práticas garante que o BITIO opere com segurança robusta em todas as camadas, desde o código até a infraestrutura, mantendo conformidade com regulamentações de proteção de dados.