Segurança Web em 2025: OWASP Top 10 e Como Proteger Suas Aplicações JavaScript
Olá HaWkers, com ataques cibernéticos aumentando exponencialmente, segurança deixou de ser responsabilidade apenas de especialistas. Todo desenvolvedor precisa conhecer OWASP Top 10 e implementar proteções básicas.
Vamos explorar as vulnerabilidades mais comuns e como proteger suas aplicações JavaScript.
OWASP Top 10: As Vulnerabilidades Críticas
const owaspTop10_2025 = {
1: 'Broken Access Control',
2: 'Cryptographic Failures',
3: 'Injection (SQL, XSS, etc)',
4: 'Insecure Design',
5: 'Security Misconfiguration',
6: 'Vulnerable Components',
7: 'Authentication Failures',
8: 'Software and Data Integrity',
9: 'Security Logging Failures',
10: 'Server-Side Request Forgery (SSRF)'
};
1. Prevenindo XSS (Cross-Site Scripting)
// ❌ VULNERÁVEL - Nunca faça isso!
function renderUserInput(input) {
document.getElementById('output').innerHTML = input;
// Se input = "<script>alert('XSS')</script>"
// Script executa!
}
// ✅ SEGURO - Sanitize input
import DOMPurify from 'dompurify';
function renderUserInputSafe(input) {
const clean = DOMPurify.sanitize(input);
document.getElementById('output').innerHTML = clean;
}
// ✅ AINDA MAIS SEGURO - Use textContent
function renderText(input) {
document.getElementById('output').textContent = input;
// HTML não é interpretado
}
// React automaticamente escapa
function UserProfile({ username }) {
return <div>{username}</div>; // Safe!
}2. SQL Injection Prevention
// ❌ VULNERÁVEL - String concatenation
async function getUser(userId) {
const query = `SELECT * FROM users WHERE id = ${userId}`;
// Se userId = "1 OR 1=1", retorna TODOS usuários!
return await db.query(query);
}
// ✅ SEGURO - Prepared statements
async function getUserSafe(userId) {
const query = 'SELECT * FROM users WHERE id = ?';
return await db.query(query, [userId]);
}
// ✅ ORM ainda mais seguro
async function getUserORM(userId) {
return await User.findById(userId);
// ORM sanitiza automaticamente
}
3. Autenticação Segura
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
class AuthService {
// Registrar usuário
async register(email, password) {
// Validar senha forte
if (password.length < 12) {
throw new Error('Senha deve ter mínimo 12 caracteres');
}
// Hash com bcrypt (NUNCA salve senha plain text!)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
await db.users.create({
email,
password: hashedPassword
});
}
// Login
async login(email, password) {
const user = await db.users.findOne({ email });
if (!user) {
// ✅ Mensagem genérica (não revela se email existe)
throw new Error('Credenciais inválidas');
}
// Verificar senha
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
throw new Error('Credenciais inválidas');
}
// JWT com expiração curta
const token = jwt.sign(
{ userId: user.id, email: user.email },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
return { token, user: { id: user.id, email: user.email } };
}
// Verificar token
verifyToken(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET);
} catch {
throw new Error('Token inválido');
}
}
}4. CSRF Protection
// Backend - Express
import csrf from 'csurf';
const csrfProtection = csrf({ cookie: true });
app.post('/api/transfer', csrfProtection, async (req, res) => {
// Token CSRF validado automaticamente
await processTransfer(req.body);
res.json({ success: true });
});
// Frontend - Enviar token
async function transferMoney(amount, to) {
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
await fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
},
body: JSON.stringify({ amount, to })
});
}
5. Validação de Input
import { z } from 'zod';
// Schema de validação
const userSchema = z.object({
email: z.string().email(),
age: z.number().min(18).max(120),
username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/)
});
// Validar input
async function createUser(data) {
try {
// Valida e parse
const validated = userSchema.parse(data);
// ✅ Dados garantidamente válidos
return await db.users.create(validated);
} catch (error) {
throw new Error('Dados inválidos');
}
}6. Rate Limiting
import rateLimit from 'express-rate-limit';
// Prevenir brute force
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 5, // 5 tentativas
message: 'Muitas tentativas de login. Tente em 15 minutos.'
});
app.post('/api/login', loginLimiter, async (req, res) => {
// Login logic
});
// Rate limit geral
const apiLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minuto
max: 100 // 100 requests
});
app.use('/api/', apiLimiter);7. Secure Headers
import helmet from 'helmet';
// Express - Helmet configura headers seguros
app.use(helmet());
// Headers importantes:
const securityHeaders = {
'Content-Security-Policy': "default-src 'self'",
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'Strict-Transport-Security': 'max-age=31536000',
'X-XSS-Protection': '1; mode=block'
};Checklist de Segurança
const securityChecklist = [
'✅ Validar TODO input do usuário',
'✅ Usar prepared statements (SQL)',
'✅ Sanitizar output HTML',
'✅ Implementar rate limiting',
'✅ HTTPS em produção (sempre!)',
'✅ Passwords hasheadas com bcrypt',
'✅ JWT com expiração curta',
'✅ CSRF tokens em forms',
'✅ Security headers (Helmet)',
'✅ Dependências atualizadas',
'✅ Secrets em env vars',
'✅ Logging de eventos de segurança',
'✅ CORS configurado corretamente'
];Segurança não é opcional em 2025. Com ataques cada vez mais sofisticados, todo desenvolvedor é responsável por código seguro.
Bora pra cima! 🦅
🎯 Desenvolvedores Seguros Têm Mais Valor
Conhecimento de segurança diferencia desenvolvedores júniors de profissionais completos. Invista em conhecimento sólido.
Comece agora:
- R$9,90 (pagamento único)

