Pular para o conteúdo principal

Políticas de Segurança

Estabelecer políticas de segurança robustas é fundamental para proteger credenciais e dados sensíveis no n8n. Neste guia, você aprenderá a criar e implementar políticas de segurança abrangentes.

O que você aprenderá

  • Políticas de senha e autenticação
  • Criptografia e armazenamento seguro
  • Controle de acesso e auditoria
  • Compliance com LGPD e regulamentações
  • Boas práticas de segurança

Políticas de Senha

1. Requisitos de Senha

Política Mínima:

{
  "minLength": 12,
  "requireUppercase": true,
  "requireLowercase": true,
  "requireNumbers": true,
  "requireSpecialChars": true,
  "maxAge": 90,
  "preventReuse": 5,
  "lockoutAttempts": 5,
  "lockoutDuration": 900
}

Política Avançada:

{
  "minLength": 16,
  "requireUppercase": true,
  "requireLowercase": true,
  "requireNumbers": true,
  "requireSpecialChars": true,
  "maxAge": 60,
  "preventReuse": 10,
  "lockoutAttempts": 3,
  "lockoutDuration": 1800,
  "require2FA": true,
  "passwordHistory": 10
}

2. Implementação

Configuração via Variáveis de Ambiente:

# Políticas de senha
N8N_PASSWORD_MIN_LENGTH=12
N8N_PASSWORD_REQUIRE_UPPERCASE=true
N8N_PASSWORD_REQUIRE_LOWERCASE=true
N8N_PASSWORD_REQUIRE_NUMBERS=true
N8N_PASSWORD_REQUIRE_SPECIAL_CHARS=true
N8N_PASSWORD_MAX_AGE=90
N8N_PASSWORD_PREVENT_REUSE=5

# Bloqueio de conta
N8N_LOGIN_ATTEMPTS_LIMIT=5
N8N_LOGIN_ATTEMPTS_TIMEOUT=900

Validação Customizada:

// Code node para validação de senha
function validatePassword(password) {
  const minLength = 12;
  const hasUppercase = /[A-Z]/.test(password);
  const hasLowercase = /[a-z]/.test(password);
  const hasNumbers = /\d/.test(password);
  const hasSpecialChars = /[!@#$%^&*(),.?":{}|<>]/.test(password);
  
  const errors = [];
  
  if (password.length < minLength) {
    errors.push(`Senha deve ter pelo menos ${minLength} caracteres`);
  }
  if (!hasUppercase) errors.push('Incluir pelo menos uma letra maiúscula');
  if (!hasLowercase) errors.push('Incluir pelo menos uma letra minúscula');
  if (!hasNumbers) errors.push('Incluir pelo menos um número');
  if (!hasSpecialChars) errors.push('Incluir pelo menos um caractere especial');
  
  return {
    isValid: errors.length === 0,
    errors: errors
  };
}

Criptografia e Armazenamento

1. Criptografia de Credenciais

Configuração de Criptografia:

# Chave de criptografia (32 bytes)
N8N_ENCRYPTION_KEY=your-32-byte-encryption-key-here

# Algoritmo de criptografia
N8N_ENCRYPTION_ALGORITHM=aes-256-gcm

# IV (Initialization Vector)
N8N_ENCRYPTION_IV=your-16-byte-iv-here

Implementação de Criptografia:

// Função para criptografar credenciais
async function encryptCredential(credential) {
  const crypto = require('crypto');
  const algorithm = 'aes-256-gcm';
  const key = Buffer.from(process.env.N8N_ENCRYPTION_KEY, 'hex');
  const iv = crypto.randomBytes(16);
  
  const cipher = crypto.createCipher(algorithm, key);
  cipher.setAAD(Buffer.from('n8n-credential', 'utf8'));
  
  let encrypted = cipher.update(JSON.stringify(credential), 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  const authTag = cipher.getAuthTag();
  
  return {
    encrypted: encrypted,
    iv: iv.toString('hex'),
    authTag: authTag.toString('hex')
  };
}

// Função para descriptografar credenciais
async function decryptCredential(encryptedData) {
  const crypto = require('crypto');
  const algorithm = 'aes-256-gcm';
  const key = Buffer.from(process.env.N8N_ENCRYPTION_KEY, 'hex');
  const iv = Buffer.from(encryptedData.iv, 'hex');
  const authTag = Buffer.from(encryptedData.authTag, 'hex');
  
  const decipher = crypto.createDecipher(algorithm, key);
  decipher.setAAD(Buffer.from('n8n-credential', 'utf8'));
  decipher.setAuthTag(authTag);
  
  let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  
  return JSON.parse(decrypted);
}

2. Armazenamento Seguro

Configuração de Banco de Dados:

# PostgreSQL com SSL
N8N_DB_TYPE=postgresdb
N8N_DB_POSTGRESDB_HOST=your-db-host
N8N_DB_POSTGRESDB_PORT=5432
N8N_DB_POSTGRESDB_DATABASE=n8n
N8N_DB_POSTGRESDB_USER=n8n_user
N8N_DB_POSTGRESDB_PASSWORD=secure-password
N8N_DB_POSTGRESDB_SCHEMA=public
N8N_DB_POSTGRESDB_SSL_REJECT_UNAUTHORIZED=true
N8N_DB_POSTGRESDB_SSL_CA=/path/to/ca-certificate.crt

Backup Seguro:

#!/bin/bash
# backup_credentials.sh

# Configurações
DB_HOST="your-db-host"
DB_NAME="n8n"
DB_USER="n8n_user"
BACKUP_DIR="/secure/backup/credentials"
ENCRYPTION_KEY="your-backup-encryption-key"

# Criar backup criptografado
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME --table=credentials \
  | gzip \
  | openssl enc -aes-256-cbc -salt -k $ENCRYPTION_KEY \
  > $BACKUP_DIR/credentials_$(date +%Y%m%d_%H%M%S).sql.gz.enc

# Limpar backups antigos (manter 30 dias)
find $BACKUP_DIR -name "credentials_*.sql.gz.enc" -mtime +30 -delete

Controle de Acesso

1. Políticas de Acesso

Princípio do Menor Privilégio:

{
  "accessPolicies": {
    "developers": {
      "canCreate": true,
      "canEdit": true,
      "canUse": true,
      "canDelete": false,
      "restrictedCredentials": ["production", "financial"]
    },
    "operators": {
      "canCreate": false,
      "canEdit": false,
      "canUse": true,
      "canDelete": false,
      "allowedCredentials": ["monitoring", "backup"]
    },
    "admins": {
      "canCreate": true,
      "canEdit": true,
      "canUse": true,
      "canDelete": true,
      "allCredentials": true
    }
  }
}

Controle por Ambiente:

{
  "environmentPolicies": {
    "development": {
      "maxCredentialAge": 30,
      "requireRotation": false,
      "allowedTypes": ["api_key", "basic_auth", "oauth2"]
    },
    "staging": {
      "maxCredentialAge": 60,
      "requireRotation": true,
      "allowedTypes": ["api_key", "basic_auth", "oauth2", "certificate"]
    },
    "production": {
      "maxCredentialAge": 90,
      "requireRotation": true,
      "allowedTypes": ["api_key", "basic_auth", "oauth2", "certificate", "saml"]
    }
  }
}

2. Auditoria e Logging

Logs de Auditoria:

// Middleware para logging de acesso a credenciais
function logCredentialAccess(req, res, next) {
  const originalSend = res.send;
  
  res.send = function(data) {
    // Log de acesso a credenciais
    if (req.path.includes('/credentials')) {
      const auditLog = {
        timestamp: new Date().toISOString(),
        user: req.user?.email || 'unknown',
        action: req.method,
        resource: req.path,
        ip: req.ip,
        userAgent: req.get('User-Agent'),
        success: res.statusCode < 400
      };
      
      // Salvar log de auditoria
      saveAuditLog(auditLog);
    }
    
    originalSend.call(this, data);
  };
  
  next();
}

Relatórios de Auditoria:

-- Query para relatório de acesso a credenciais
SELECT 
  u.email as user_email,
  c.name as credential_name,
  c.type as credential_type,
  COUNT(*) as access_count,
  MAX(a.timestamp) as last_access,
  MIN(a.timestamp) as first_access
FROM audit_logs a
JOIN users u ON a.user_id = u.id
JOIN credentials c ON a.resource_id = c.id
WHERE a.resource_type = 'credential'
  AND a.timestamp >= NOW() - INTERVAL '30 days'
GROUP BY u.email, c.name, c.type
ORDER BY access_count DESC;

Compliance e Regulamentações

1. LGPD (Lei Geral de Proteção de Dados)

Políticas de Conformidade:

{
  "lgpdCompliance": {
    "dataRetention": {
      "credentials": "90 days",
      "auditLogs": "5 years",
      "userActivity": "2 years"
    },
    "dataProcessing": {
      "purpose": "Workflow automation",
      "legalBasis": "Legitimate interest",
      "dataMinimization": true
    },
    "userRights": {
      "access": true,
      "rectification": true,
      "erasure": true,
      "portability": true
    }
  }
}

Implementação de Direitos LGPD:

// Função para atender solicitação de acesso (LGPD)
async function handleDataAccessRequest(userId) {
  const userData = await getUserData(userId);
  const credentials = await getUserCredentials(userId);
  const activity = await getUserActivity(userId);
  
  return {
    personalData: {
      email: userData.email,
      name: userData.name,
      role: userData.role
    },
    credentials: credentials.map(c => ({
      name: c.name,
      type: c.type,
      lastUsed: c.lastUsed
    })),
    activity: activity.map(a => ({
      action: a.action,
      timestamp: a.timestamp,
      resource: a.resource
    }))
  };
}

// Função para atender solicitação de exclusão (LGPD)
async function handleDataErasureRequest(userId) {
  // Anonimizar dados pessoais
  await anonymizeUserData(userId);
  
  // Revogar credenciais
  await revokeUserCredentials(userId);
  
  // Manter logs de auditoria (requisito legal)
  await logDataErasure(userId);
  
  return { success: true, message: 'Dados anonimizados com sucesso' };
}

2. ISO 27001

Controles de Segurança:

{
  "iso27001Controls": {
    "A.9.2.1": {
      "name": "User registration and de-registration",
      "implementation": "Automated user lifecycle management",
      "evidence": "User creation/deletion logs"
    },
    "A.9.2.3": {
      "name": "Access provisioning",
      "implementation": "Role-based access control",
      "evidence": "Permission assignment logs"
    },
    "A.9.4.1": {
      "name": "Information access restriction",
      "implementation": "Credential encryption and access controls",
      "evidence": "Encryption audit logs"
    },
    "A.12.4.1": {
      "name": "Event logging",
      "implementation": "Comprehensive audit logging",
      "evidence": "Audit trail reports"
    }
  }
}

Boas Práticas

1. Gestão de Credenciais

Rotação Automática:

// Script para rotação automática de credenciais
async function rotateCredentials() {
  const credentials = await getExpiringCredentials(30); // 30 dias
  
  for (const credential of credentials) {
    // Notificar administrador
    await notifyAdmin({
      type: 'credential_expiry',
      credential: credential.name,
      expiryDate: credential.expiryDate,
      daysUntilExpiry: credential.daysUntilExpiry
    });
    
    // Rotação automática para APIs que suportam
    if (credential.supportsAutoRotation) {
      await rotateCredential(credential.id);
    }
  }
}

// Agendar rotação diária
setInterval(rotateCredentials, 24 * 60 * 60 * 1000);

Validação de Credenciais:

// Função para validar credenciais periodicamente
async function validateCredentials() {
  const credentials = await getAllActiveCredentials();
  
  for (const credential of credentials) {
    try {
      const isValid = await testCredential(credential);
      
      if (!isValid) {
        await markCredentialInvalid(credential.id);
        await notifyAdmin({
          type: 'credential_invalid',
          credential: credential.name,
          lastTest: new Date()
        });
      }
    } catch (error) {
      console.error(`Erro ao validar credencial ${credential.name}:`, error);
    }
  }
}

2. Monitoramento e Alertas

Alertas de Segurança:

// Monitoramento de atividades suspeitas
async function monitorSuspiciousActivity() {
  const recentActivity = await getRecentActivity(3600000); // 1 hora
  
  // Múltiplas tentativas de acesso
  const accessAttempts = groupBy(recentActivity, 'user');
  for (const [user, attempts] of Object.entries(accessAttempts)) {
    if (attempts.length > 10) {
      await triggerAlert({
        type: 'suspicious_activity',
        user: user,
        activity: 'multiple_access_attempts',
        count: attempts.length
      });
    }
  }
  
  // Acesso fora do horário comercial
  const offHoursAccess = recentActivity.filter(activity => {
    const hour = new Date(activity.timestamp).getHours();
    return hour < 8 || hour > 18;
  });
  
  if (offHoursAccess.length > 0) {
    await triggerAlert({
      type: 'off_hours_access',
      activities: offHoursAccess
    });
  }
}

3. Treinamento e Conscientização

Programa de Treinamento:

{
  "securityTraining": {
    "frequency": "quarterly",
    "topics": [
      "Políticas de senha",
      "Phishing awareness",
      "Credential management",
      "Incident response",
      "Data protection"
    ],
    "assessments": [
      "Password strength test",
      "Phishing simulation",
      "Security policy quiz"
    ],
    "completionTracking": true
  }
}

Exemplos Práticos

Exemplo 1: Política de Senha Corporativa

Implementação Completa:

// Validador de senha corporativo
class CorporatePasswordValidator {
  constructor() {
    this.minLength = 12;
    this.requireUppercase = true;
    this.requireLowercase = true;
    this.requireNumbers = true;
    this.requireSpecialChars = true;
    this.forbiddenWords = ['password', '123456', 'qwerty', 'admin'];
  }
  
  validate(password) {
    const errors = [];
    
    // Verificar comprimento
    if (password.length < this.minLength) {
      errors.push(`Senha deve ter pelo menos ${this.minLength} caracteres`);
    }
    
    // Verificar complexidade
    if (this.requireUppercase && !/[A-Z]/.test(password)) {
      errors.push('Incluir pelo menos uma letra maiúscula');
    }
    
    if (this.requireLowercase && !/[a-z]/.test(password)) {
      errors.push('Incluir pelo menos uma letra minúscula');
    }
    
    if (this.requireNumbers && !/\d/.test(password)) {
      errors.push('Incluir pelo menos um número');
    }
    
    if (this.requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
      errors.push('Incluir pelo menos um caractere especial');
    }
    
    // Verificar palavras proibidas
    const lowerPassword = password.toLowerCase();
    for (const word of this.forbiddenWords) {
      if (lowerPassword.includes(word)) {
        errors.push(`Senha não pode conter '${word}'`);
      }
    }
    
    // Verificar sequências
    if (this.hasSequentialChars(password)) {
      errors.push('Senha não pode conter sequências (ex: 123, abc)');
    }
    
    return {
      isValid: errors.length === 0,
      errors: errors,
      strength: this.calculateStrength(password)
    };
  }
  
  calculateStrength(password) {
    let score = 0;
    
    // Comprimento
    score += Math.min(password.length * 4, 20);
    
    // Complexidade
    if (/[A-Z]/.test(password)) score += 10;
    if (/[a-z]/.test(password)) score += 10;
    if (/\d/.test(password)) score += 10;
    if (/[!@#$%^&*(),.?":{}|<>]/.test(password)) score += 10;
    
    // Variedade de caracteres
    const uniqueChars = new Set(password).size;
    score += Math.min(uniqueChars * 2, 20);
    
    return {
      score: Math.min(score, 100),
      level: score < 40 ? 'weak' : score < 70 ? 'medium' : 'strong'
    };
  }
  
  hasSequentialChars(password) {
    const sequences = ['123', '234', '345', 'abc', 'bcd', 'cde'];
    const lowerPassword = password.toLowerCase();
    
    return sequences.some(seq => lowerPassword.includes(seq));
  }
}

Exemplo 2: Sistema de Auditoria

Implementação de Auditoria Completa:

// Sistema de auditoria de credenciais
class CredentialAuditor {
  constructor() {
    this.auditLog = [];
  }
  
  logAccess(user, credential, action, success, details = {}) {
    const auditEntry = {
      timestamp: new Date().toISOString(),
      user: user.email,
      userId: user.id,
      credential: credential.name,
      credentialId: credential.id,
      action: action,
      success: success,
      ip: details.ip || 'unknown',
      userAgent: details.userAgent || 'unknown',
      details: details
    };
    
    this.auditLog.push(auditEntry);
    this.saveAuditLog(auditEntry);
    
    // Verificar atividades suspeitas
    this.checkSuspiciousActivity(user.id);
  }
  
  async checkSuspiciousActivity(userId) {
    const recentActivity = this.auditLog.filter(
      entry => entry.userId === userId && 
      new Date(entry.timestamp) > new Date(Date.now() - 3600000) // 1 hora
    );
    
    // Múltiplas tentativas de acesso
    if (recentActivity.length > 10) {
      await this.triggerAlert({
        type: 'multiple_access_attempts',
        user: recentActivity[0].user,
        count: recentActivity.length,
        timeframe: '1 hour'
      });
    }
    
    // Acesso a múltiplas credenciais
    const uniqueCredentials = new Set(recentActivity.map(a => a.credentialId));
    if (uniqueCredentials.size > 5) {
      await this.triggerAlert({
        type: 'multiple_credential_access',
        user: recentActivity[0].user,
        credentialCount: uniqueCredentials.size,
        timeframe: '1 hour'
      });
    }
  }
  
  async generateAuditReport(startDate, endDate) {
    const filteredLogs = this.auditLog.filter(
      entry => new Date(entry.timestamp) >= startDate && 
               new Date(entry.timestamp) <= endDate
    );
    
    const report = {
      period: { start: startDate, end: endDate },
      totalAccess: filteredLogs.length,
      successfulAccess: filteredLogs.filter(l => l.success).length,
      failedAccess: filteredLogs.filter(l => !l.success).length,
      users: this.getUniqueUsers(filteredLogs),
      credentials: this.getUniqueCredentials(filteredLogs),
      suspiciousActivity: await this.getSuspiciousActivity(filteredLogs)
    };
    
    return report;
  }
  
  getUniqueUsers(logs) {
    return [...new Set(logs.map(l => l.user))];
  }
  
  getUniqueCredentials(logs) {
    return [...new Set(logs.map(l => l.credential))];
  }
  
  async getSuspiciousActivity(logs) {
    // Implementar lógica para detectar atividades suspeitas
    return [];
  }
  
  async saveAuditLog(entry) {
    // Salvar no banco de dados
    await db.auditLogs.create(entry);
  }
  
  async triggerAlert(alert) {
    // Enviar alerta para administradores
    await notificationService.sendAlert(alert);
  }
}

Exemplo 3: Compliance LGPD

Implementação de Direitos LGPD:

// Sistema de compliance LGPD
class LGPDCompliance {
  constructor() {
    this.dataRetentionPolicies = {
      credentials: 90, // dias
      auditLogs: 1825, // 5 anos
      userActivity: 730 // 2 anos
    };
  }
  
  async handleDataAccessRequest(userId) {
    const user = await this.getUserData(userId);
    const credentials = await this.getUserCredentials(userId);
    const activity = await this.getUserActivity(userId);
    
    const dataPortfolio = {
      personalData: {
        name: user.name,
        email: user.email,
        role: user.role,
        createdAt: user.createdAt,
        lastLogin: user.lastLogin
      },
      credentials: credentials.map(c => ({
        name: c.name,
        type: c.type,
        createdAt: c.createdAt,
        lastUsed: c.lastUsed,
        permissions: c.permissions
      })),
      activity: activity.map(a => ({
        action: a.action,
        timestamp: a.timestamp,
        resource: a.resource,
        ip: a.ip
      }))
    };
    
    // Registrar solicitação de acesso
    await this.logDataRequest(userId, 'access');
    
    return dataPortfolio;
  }
  
  async handleDataRectificationRequest(userId, corrections) {
    const user = await this.getUserData(userId);
    
    // Aplicar correções
    for (const [field, value] of Object.entries(corrections)) {
      if (this.isEditableField(field)) {
        user[field] = value;
      }
    }
    
    await this.updateUserData(userId, user);
    await this.logDataRequest(userId, 'rectification', corrections);
    
    return { success: true, message: 'Dados corrigidos com sucesso' };
  }
  
  async handleDataErasureRequest(userId) {
    // Anonimizar dados pessoais
    await this.anonymizeUserData(userId);
    
    // Revogar credenciais
    await this.revokeUserCredentials(userId);
    
    // Manter logs de auditoria (requisito legal)
    await this.logDataRequest(userId, 'erasure');
    
    return { success: true, message: 'Dados anonimizados com sucesso' };
  }
  
  async handleDataPortabilityRequest(userId) {
    const data = await this.handleDataAccessRequest(userId);
    
    // Exportar em formato estruturado
    const exportData = {
      format: 'json',
      timestamp: new Date().toISOString(),
      data: data
    };
    
    await this.logDataRequest(userId, 'portability');
    
    return exportData;
  }
  
  async anonymizeUserData(userId) {
    const anonymizedData = {
      name: 'ANONYMIZED',
      email: `anonymous_${userId}@anonymized.com`,
      role: 'ANONYMIZED'
    };
    
    await this.updateUserData(userId, anonymizedData);
  }
  
  async revokeUserCredentials(userId) {
    const credentials = await this.getUserCredentials(userId);
    
    for (const credential of credentials) {
      await this.revokeCredential(credential.id);
    }
  }
  
  isEditableField(field) {
    const editableFields = ['name', 'email', 'role'];
    return editableFields.includes(field);
  }
  
  async logDataRequest(userId, requestType, details = {}) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      userId: userId,
      requestType: requestType,
      details: details
    };
    
    await db.lgpdRequests.create(logEntry);
  }
}

Troubleshooting

Problemas Comuns

Políticas não aplicadas:

  • Verifique configuração de variáveis de ambiente
  • Confirme reinicialização do n8n
  • Teste validação de senha
  • Verifique logs de erro

Criptografia falha:

  • Confirme chave de criptografia
  • Verifique algoritmo de criptografia
  • Teste descriptografia
  • Verifique permissões de arquivo

Auditoria não funciona:

  • Verifique configuração de logs
  • Confirme permissões de banco
  • Teste escrita de logs
  • Verifique espaço em disco

Debugging

Ferramentas úteis:

# Testar política de senha
curl -X POST "https://your-n8n.com/api/v1/users" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"weak"}'

# Verificar logs de auditoria
tail -f /var/log/n8n/audit.log

# Testar criptografia
openssl enc -aes-256-gcm -k "test-key" -in test.txt -out test.enc

Próximos Passos

  1. Implemente políticas de senha robustas
  2. Configure criptografia de credenciais
  3. Estabeleça controle de acesso granular
  4. Implemente auditoria completa
  5. Configure compliance LGPD

Recursos Relacionados


Pronto para proteger? Comece implementando políticas de senha robustas!