Loto / src /utils /SecurityEnhanced.ts
Raí Santos
oi
4c1e4ec
/**
* Sistema de Segurança Avançado
* Implementa múltiplas camadas de proteção e monitoramento
*/
interface SecurityConfig {
enableCSP: boolean;
enableXSSProtection: boolean;
enableRateLimiting: boolean;
enableSecurityHeaders: boolean;
enableIntegrityChecks: boolean;
}
interface SecurityThreat {
type: string;
severity: 'low' | 'medium' | 'high' | 'critical';
details: any;
timestamp: number;
mitigated: boolean;
}
export class SecurityEnhanced {
private static instance: SecurityEnhanced;
private config: SecurityConfig;
private threats: SecurityThreat[] = [];
private isEnabled = true;
private constructor() {
this.config = {
enableCSP: true,
enableXSSProtection: true,
enableRateLimiting: true,
enableSecurityHeaders: true,
enableIntegrityChecks: true
};
}
static getInstance(): SecurityEnhanced {
if (!SecurityEnhanced.instance) {
SecurityEnhanced.instance = new SecurityEnhanced();
}
return SecurityEnhanced.instance;
}
/**
* Inicializar todas as proteções de segurança
*/
initialize(): void {
if (!this.isEnabled) return;
console.log('🛡️ Inicializando sistema de segurança avançado...');
this.setupContentSecurityPolicy();
this.setupSecurityHeaders();
this.setupXSSProtection();
this.setupIntegrityChecks();
this.setupThreatMonitoring();
this.setupSecureStorage();
}
private setupContentSecurityPolicy(): void {
if (!this.config.enableCSP) return;
const csp = {
'default-src': ["'self'"],
'script-src': [
"'self'",
"'unsafe-inline'", // Necessário para React em desenvolvimento
"'unsafe-eval'", // Necessário para desenvolvimento
'https://servicebus2.caixa.gov.br',
'https://brasilapi.com.br'
],
'style-src': [
"'self'",
"'unsafe-inline'", // Necessário para Tailwind CSS
'https://fonts.googleapis.com'
],
'font-src': [
"'self'",
'https://fonts.gstatic.com'
],
'connect-src': [
"'self'",
'https://servicebus2.caixa.gov.br',
'https://brasilapi.com.br',
'https://api.loterias-caixa.com'
],
'img-src': [
"'self'",
'data:',
'https:'
],
'frame-ancestors': ["'none'"],
'base-uri': ["'self'"],
'form-action': ["'self'"]
};
const cspString = Object.entries(csp)
.map(([directive, sources]) => `${directive} ${sources.join(' ')}`)
.join('; ');
// Em produção, seria configurado no servidor
if (process.env.NODE_ENV === 'development') {
console.log('🛡️ CSP configurado:', cspString);
}
}
private setupSecurityHeaders(): void {
if (!this.config.enableSecurityHeaders) return;
// Headers que seriam configurados no servidor
const securityHeaders = {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'camera=(), microphone=(), geolocation=()',
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
};
console.log('🛡️ Security headers configurados:', securityHeaders);
}
private setupXSSProtection(): void {
if (!this.config.enableXSSProtection) return;
// Monitorar tentativas de XSS
this.monitorDOMChanges();
this.validateUserInputs();
this.sanitizeURLParameters();
}
private monitorDOMChanges(): void {
if (typeof window === 'undefined') return;
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
const element = node as Element;
// Verificar scripts suspeitos
if (element.tagName === 'SCRIPT') {
const src = element.getAttribute('src');
const inline = element.textContent;
if (src && !this.isAllowedScriptSource(src)) {
this.recordThreat('unauthorized-script', 'high', { src });
element.remove();
}
if (inline && this.containsSuspiciousCode(inline)) {
this.recordThreat('suspicious-inline-script', 'high', { code: inline.substring(0, 100) });
element.remove();
}
}
// Verificar iframes suspeitos
if (element.tagName === 'IFRAME') {
const src = element.getAttribute('src');
if (src && !this.isAllowedFrameSource(src)) {
this.recordThreat('unauthorized-iframe', 'high', { src });
element.remove();
}
}
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
console.log('🛡️ Monitoramento de DOM ativo para XSS');
}
private validateUserInputs(): void {
// Interceptar inputs do usuário
document.addEventListener('input', (event) => {
const target = event.target as HTMLInputElement;
if (target && target.value) {
const sanitized = this.sanitizeInput(target.value);
if (sanitized !== target.value) {
this.recordThreat('xss-attempt', 'medium', {
original: target.value.substring(0, 100),
sanitized: sanitized.substring(0, 100)
});
target.value = sanitized;
}
}
});
console.log('🛡️ Validação de inputs ativa');
}
private sanitizeURLParameters(): void {
if (typeof window === 'undefined') return;
const params = new URLSearchParams(window.location.search);
let hasThreats = false;
params.forEach((value, key) => {
const sanitized = this.sanitizeInput(value);
if (sanitized !== value) {
this.recordThreat('url-xss-attempt', 'medium', {
parameter: key,
original: value.substring(0, 100)
});
params.set(key, sanitized);
hasThreats = true;
}
});
if (hasThreats) {
const newUrl = `${window.location.pathname}?${params.toString()}`;
window.history.replaceState({}, '', newUrl);
console.log('🛡️ Parâmetros URL sanitizados');
}
}
private setupIntegrityChecks(): void {
if (!this.config.enableIntegrityChecks) return;
// Verificar integridade de recursos externos
const externalScripts = document.querySelectorAll('script[src]');
const externalStyles = document.querySelectorAll('link[rel="stylesheet"][href]');
Array.from(externalScripts).concat(Array.from(externalStyles)).forEach(element => {
if (!element.hasAttribute('integrity')) {
const src = element.getAttribute('src') || element.getAttribute('href');
if (src && this.isExternalResource(src)) {
this.recordThreat('missing-integrity', 'low', { src });
}
}
});
console.log('🛡️ Verificação de integridade ativa');
}
private setupThreatMonitoring(): void {
// Monitorar atividades suspeitas
this.monitorConsoleAccess();
this.monitorDevToolsUsage();
this.monitorSuspiciousNetworkActivity();
}
private monitorConsoleAccess(): void {
// Detectar tentativas de acesso ao console em produção
if (process.env.NODE_ENV === 'production') {
const originalConsole = { ...console };
['log', 'warn', 'error', 'debug'].forEach(method => {
(console as any)[method] = (...args: any[]) => {
// Em produção, log suspeito
if (args.some(arg =>
typeof arg === 'string' &&
(arg.includes('eval') || arg.includes('Function') || arg.includes('script'))
)) {
this.recordThreat('suspicious-console-access', 'low', { args: args.slice(0, 3) });
}
return (originalConsole as any)[method](...args);
};
});
}
}
private monitorDevToolsUsage(): void {
// Detectar abertura do DevTools
let devtools = { open: false };
setInterval(() => {
const start = performance.now();
debugger; // eslint-disable-line no-debugger
const end = performance.now();
if (end - start > 100) { // DevTools likely open
if (!devtools.open) {
devtools.open = true;
this.recordThreat('devtools-opened', 'low', { timestamp: Date.now() });
}
} else {
devtools.open = false;
}
}, 1000);
}
private monitorSuspiciousNetworkActivity(): void {
// Interceptar fetch para monitorar requisições suspeitas
const originalFetch = window.fetch;
window.fetch = async (...args) => {
const url = args[0].toString();
// Verificar URLs suspeitas
if (this.isSuspiciousURL(url)) {
this.recordThreat('suspicious-network-request', 'medium', { url });
throw new Error('Requisição bloqueada por segurança');
}
return originalFetch(...args);
};
}
private setupSecureStorage(): void {
// Implementar armazenamento seguro
const originalSetItem = localStorage.setItem;
const originalGetItem = localStorage.getItem;
localStorage.setItem = (key: string, value: string) => {
// Criptografar dados sensíveis
if (this.isSensitiveData(key)) {
value = this.encryptData(value);
}
return originalSetItem.call(localStorage, key, value);
};
localStorage.getItem = (key: string) => {
const value = originalGetItem.call(localStorage, key);
if (value && this.isSensitiveData(key)) {
return this.decryptData(value);
}
return value;
};
console.log('🛡️ Armazenamento seguro configurado');
}
private sanitizeInput(input: string): string {
return input
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
.replace(/javascript:/gi, '')
.replace(/on\w+=/gi, '')
.replace(/eval\(/gi, '')
.replace(/Function\(/gi, '')
.replace(/setTimeout\(/gi, '')
.replace(/setInterval\(/gi, '');
}
private containsSuspiciousCode(code: string): boolean {
const suspiciousPatterns = [
/eval\s*\(/,
/Function\s*\(/,
/document\.write/,
/innerHTML\s*=/,
/outerHTML\s*=/,
/javascript:/,
/data:text\/html/,
/execScript/,
/setInterval.*eval/,
/setTimeout.*eval/
];
return suspiciousPatterns.some(pattern => pattern.test(code));
}
private isAllowedScriptSource(src: string): boolean {
const allowedDomains = [
window.location.origin,
'https://servicebus2.caixa.gov.br',
'https://brasilapi.com.br',
'https://fonts.googleapis.com',
'https://fonts.gstatic.com'
];
return allowedDomains.some(domain => src.startsWith(domain));
}
private isAllowedFrameSource(src: string): boolean {
// Por padrão, não permitir iframes externos
return src.startsWith(window.location.origin);
}
private isExternalResource(src: string): boolean {
return !src.startsWith(window.location.origin) &&
(src.startsWith('http://') || src.startsWith('https://'));
}
private isSuspiciousURL(url: string): boolean {
const suspiciousPatterns = [
/bit\.ly/,
/tinyurl/,
/malware/,
/phishing/,
/\.tk$/,
/\.ml$/
];
return suspiciousPatterns.some(pattern => pattern.test(url));
}
private isSensitiveData(key: string): boolean {
const sensitiveKeys = ['token', 'password', 'secret', 'key', 'auth'];
return sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive));
}
private encryptData(data: string): string {
// Implementação simples de encoding (em produção, usar crypto real)
return btoa(encodeURIComponent(data));
}
private decryptData(data: string): string {
try {
return decodeURIComponent(atob(data));
} catch {
return data; // Retornar original se não conseguir decodificar
}
}
private recordThreat(type: string, severity: SecurityThreat['severity'], details: any): void {
const threat: SecurityThreat = {
type,
severity,
details,
timestamp: Date.now(),
mitigated: false
};
this.threats.push(threat);
// Log baseado na severidade
const emoji = severity === 'critical' ? '🚨' : severity === 'high' ? '⚠️' : '⚡';
console.warn(`${emoji} Ameaça ${severity}: ${type}`, details);
// Auto-mitigar ameaças conhecidas
this.mitigateThreat(threat);
}
private mitigateThreat(threat: SecurityThreat): void {
switch (threat.type) {
case 'unauthorized-script':
case 'unauthorized-iframe':
// Já removido no monitoramento
threat.mitigated = true;
break;
case 'xss-attempt':
case 'url-xss-attempt':
// Já sanitizado
threat.mitigated = true;
break;
default:
// Log para investigação manual
break;
}
}
/**
* Obter relatório de segurança
*/
getSecurityReport(): {
threatsDetected: number;
threatsMitigated: number;
recentThreats: SecurityThreat[];
recommendations: string[];
} {
const recent = this.threats.filter(t => Date.now() - t.timestamp < 24 * 60 * 60 * 1000); // Last 24h
const mitigated = this.threats.filter(t => t.mitigated).length;
return {
threatsDetected: this.threats.length,
threatsMitigated: mitigated,
recentThreats: recent,
recommendations: this.generateSecurityRecommendations()
};
}
private generateSecurityRecommendations(): string[] {
const recommendations = [];
if (this.threats.some(t => t.type.includes('xss'))) {
recommendations.push('🛡️ Implementar sanitização mais rigorosa de inputs');
}
if (this.threats.some(t => t.type.includes('script'))) {
recommendations.push('🔒 Revisar Content Security Policy');
}
if (this.threats.some(t => t.severity === 'high' || t.severity === 'critical')) {
recommendations.push('🚨 Revisar logs de segurança imediatamente');
}
if (recommendations.length === 0) {
recommendations.push('✅ Sistema seguro - nenhuma ameaça significativa detectada');
}
return recommendations;
}
/**
* Limpar dados de segurança
*/
cleanup(): void {
this.threats = [];
console.log('🧹 Dados de segurança limpos');
}
/**
* Ativar/desativar sistema de segurança
*/
setEnabled(enabled: boolean): void {
this.isEnabled = enabled;
if (enabled) {
this.initialize();
}
}
}
// Singleton instance
export const securityEnhanced = SecurityEnhanced.getInstance();