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
- Implemente políticas de senha robustas
- Configure criptografia de credenciais
- Estabeleça controle de acesso granular
- Implemente auditoria completa
- Configure compliance LGPD
Recursos Relacionados
- Boas Práticas - Práticas recomendadas
- Compartilhamento - Compartilhamento seguro
- Segurança - Configurações de segurança
- LGPD - Conformidade LGPD
- Comunidade - Suporte e dicas