Este documento detalha todas as medidas de segurança implementadas no sistema Refund, seguindo as diretrizes do OWASP Top 10 2021.
Risco: Usuários podem acessar recursos não autorizados.
Mitigações Implementadas:
- ✅ Validação de IDs antes de operações
- ✅ Confirmação de ações destrutivas (remoção)
- ✅ Sem exposição de dados sensíveis no localStorage
Código:
// ExpenseListController.js
handleRemove(id) {
const confirmed = confirm('Deseja realmente remover esta despesa?');
if (!confirmed) return;
// ...
}Recomendações Futuras:
- Implementar autenticação de usuários
- Controle de acesso baseado em roles (RBAC)
- Auditoria de ações
Risco: Dados sensíveis expostos ou mal protegidos.
Mitigações Implementadas:
- ✅ Dados armazenados localmente (sem transmissão)
- ✅ Sem armazenamento de dados sensíveis (senhas, tokens)
- ✅ Preparado para HTTPS em produção
Recomendações Futuras:
- Criptografia de dados no localStorage
- HTTPS obrigatório
- Hashing de dados sensíveis
Risco: Injeção de código malicioso (XSS, SQL Injection).
Mitigações Implementadas:
// InputValidator.js
static sanitizeString(input) {
// Remove tags HTML
let sanitized = input.replace(/<[^>]*>/g, '');
// Remove caracteres de controle
sanitized = sanitized.replace(/[\x00-\x1F\x7F]/g, '');
// Normaliza espaços
sanitized = sanitized.trim().replace(/\s+/g, ' ');
return sanitized;
}// InputValidator.js
static validateCategory(categoryId, allowedCategories = []) {
// Apenas categorias na whitelist são aceitas
if (!allowedCategories.includes(sanitized)) {
return { valid: false, error: 'Categoria inválida' };
}
}// DOMHelper.js
static setTextContent(element, text) {
// Usa textContent ao invés de innerHTML
element.textContent = text;
}
static setInnerHTML(element, html) {
// Remove scripts e eventos inline
const sanitized = html
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/on\w+="[^"]*"/gi, '');
element.innerHTML = sanitized;
}Proteções:
- ✅ XSS (Cross-Site Scripting)
- ✅ HTML Injection
- ✅ Script Injection
Risco: Falhas fundamentais de design de segurança.
Mitigações Implementadas:
- ✅ Arquitetura em camadas com separação de responsabilidades
- ✅ Validação em múltiplas camadas (UI, Service, Model)
- ✅ Princípio do menor privilégio
- ✅ Fail-safe defaults (validação rejeita por padrão)
Design Seguro:
// Validação em camadas
1. UI: Validação básica
2. Service: Validação de negócio
3. Model: Validação de integridade
4. Repository: Validação de persistênciaRisco: Configurações inseguras ou padrões.
Mitigações Implementadas:
// app.js
setupSecurityHeaders() {
const cspMeta = document.createElement('meta');
cspMeta.httpEquiv = 'Content-Security-Policy';
cspMeta.content = "default-src 'self'; script-src 'self'; ...";
document.head.appendChild(cspMeta);
}<!-- index.html -->
<meta http-equiv="X-Content-Type-Options" content="nosniff" />
<meta http-equiv="X-Frame-Options" content="DENY" />
<meta name="referrer" content="strict-origin-when-cross-origin" />Headers Implementados:
- ✅
X-Content-Type-Options: nosniff- Previne MIME sniffing - ✅
X-Frame-Options: DENY- Previne clickjacking - ✅
Referrer-Policy- Controla informações de referrer - ✅
Content-Security-Policy- Restringe recursos
Risco: Uso de bibliotecas vulneráveis.
Mitigações Implementadas:
- ✅ Sem dependências externas (Vanilla JS)
- ✅ Código próprio e auditável
- ✅ Uso apenas de APIs nativas do navegador
Recomendações Futuras:
- Auditoria regular de dependências (se adicionar)
- Uso de ferramentas como
npm audit - Manter dependências atualizadas
Risco: Falhas em autenticação e gerenciamento de sessão.
Status Atual:
⚠️ Sem autenticação (aplicação local)
Preparação para Autenticação:
// Estrutura preparada para adicionar autenticação
class AuthService {
login(credentials) {
// Validação robusta
// Hash de senha
// Geração de token seguro
}
logout() {
// Limpeza de sessão
}
}Recomendações Futuras:
- Implementar autenticação JWT
- Rate limiting para login
- Bloqueio após tentativas falhadas
- Senhas com requisitos mínimos
- MFA (Multi-Factor Authentication)
Risco: Código ou dados comprometidos.
Mitigações Implementadas:
// Expense.js
validate() {
const errors = [];
if (!this.expense || this.expense.trim().length === 0) {
errors.push('Nome da despesa é obrigatório');
}
if (this.amount <= 0) {
errors.push('Valor deve ser maior que zero');
}
return { valid: errors.length === 0, errors };
}// LocalStorageAdapter.js
save(key, data) {
try {
const serializedData = JSON.stringify(data);
localStorage.setItem(key, serializedData);
} catch (error) {
console.error('Erro ao salvar:', error);
throw new Error('Não foi possível salvar os dados');
}
}Proteções:
- ✅ Validação antes de persistir
- ✅ Tratamento de erros de serialização
- ✅ Verificação de integridade de dados
Recomendações Futuras:
- Subresource Integrity (SRI) para CDNs
- Assinatura digital de dados
- Versionamento de dados
Risco: Falta de logging e monitoramento.
Implementações Atuais:
// Logging de erros
console.error('Erro ao criar despesa:', error);
console.warn('Evento desconhecido:', event);Recomendações Futuras:
- Sistema de logging estruturado
- Monitoramento de erros (Sentry, LogRocket)
- Auditoria de ações do usuário
- Alertas de segurança
- Retenção de logs
Exemplo de Implementação Futura:
class Logger {
static log(level, message, context) {
const entry = {
timestamp: new Date().toISOString(),
level,
message,
context,
userId: getCurrentUser()?.id
};
// Enviar para servidor de logs
sendToLogServer(entry);
}
}Risco: Servidor faz requisições não autorizadas.
Status Atual:
- ✅ Aplicação client-side apenas
- ✅ Sem requisições a servidores externos
- ✅ Sem processamento de URLs fornecidas pelo usuário
Preparação para Backend:
// Validação de URLs (quando implementar backend)
class URLValidator {
static isAllowed(url) {
const allowedDomains = ['api.example.com'];
const parsed = new URL(url);
return allowedDomains.includes(parsed.hostname);
}
}Princípios:
- ✅ Validar no cliente E servidor (quando implementar)
- ✅ Whitelist ao invés de blacklist
- ✅ Validação de tipo, tamanho e formato
- ✅ Rejeitar por padrão
Exemplo:
// Whitelist de categorias
const ALLOWED_CATEGORIES = ['food', 'accommodation', 'services', 'transport', 'others'];
if (!ALLOWED_CATEGORIES.includes(category)) {
throw new Error('Categoria inválida');
}Princípios:
- ✅ Usar
textContentao invés deinnerHTML - ✅ Escapar HTML quando necessário
- ✅ Sanitizar antes de renderizar
Exemplo:
// Seguro
element.textContent = userInput;
// Inseguro
element.innerHTML = userInput; // ❌ Vulnerável a XSSPrincípios:
- ✅ Não expor detalhes técnicos ao usuário
- ✅ Logar erros para debug
- ✅ Mensagens genéricas para o usuário
Exemplo:
try {
// Operação
} catch (error) {
console.error('Erro técnico:', error); // Para debug
alert('Não foi possível completar a operação'); // Para usuário
}class RateLimiter {
constructor(maxAttempts, windowMs) {
this.maxAttempts = maxAttempts;
this.windowMs = windowMs;
this.attempts = new Map();
}
isAllowed(key) {
const now = Date.now();
const userAttempts = this.attempts.get(key) || [];
// Remove tentativas antigas
const recentAttempts = userAttempts.filter(
time => now - time < this.windowMs
);
if (recentAttempts.length >= this.maxAttempts) {
return false;
}
recentAttempts.push(now);
this.attempts.set(key, recentAttempts);
return true;
}
}- Sanitização de inputs
- Validação com whitelist
- Proteção contra XSS
- Content Security Policy
- Security Headers
- Manipulação segura do DOM
- Validação em múltiplas camadas
- Tratamento de erros
- Confirmação de ações destrutivas
- Sem dependências vulneráveis
- HTTPS obrigatório
- Autenticação de usuários
- Autorização baseada em roles
- Rate limiting
- Logging estruturado
- Monitoramento de segurança
- Criptografia de dados sensíveis
- Backup e recuperação
- Testes de penetração
- Auditoria de segurança
- XSS Testing
// Tentar injetar script
Nome: <script>alert('XSS')</script>
Resultado esperado: Script não executado, texto sanitizado- HTML Injection
// Tentar injetar HTML
Nome: <img src=x onerror=alert('XSS')>
Resultado esperado: Tags removidas-
SQL Injection (N/A - sem banco de dados)
-
CSRF (N/A - sem autenticação)
describe('Security Tests', () => {
it('should sanitize XSS attempts', () => {
const malicious = '<script>alert("XSS")</script>';
const sanitized = InputValidator.sanitizeString(malicious);
expect(sanitized).not.toContain('<script>');
});
it('should reject invalid categories', () => {
const result = InputValidator.validateCategory('invalid');
expect(result.valid).toBe(false);
});
});- Defense in Depth - Múltiplas camadas de segurança
- Least Privilege - Mínimo acesso necessário
- Fail Secure - Falhar de forma segura
- Don't Trust User Input - Nunca confiar em dados do usuário
- Security by Design - Segurança desde o início
Última atualização: 2026-02-16
Nível de Segurança Atual: 🟢 Bom (para aplicação client-side)
Próximos Passos: Implementar autenticação e backend seguro