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​

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
}

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​

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);
}

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=SUA_SENHA_SEGURA_AQUI
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​

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"]
    }
  }
}

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​

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' };
}

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​

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);
    }
  }
}

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
    });
  }
}

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

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!