A Importancia da Seguranca Web
Aplicacoes web estao constantemente expostas a riscos de ataques. A OWASP (Open Web Application Security Project) publica o Top 10, que resume os riscos de seguranca mais graves.
flowchart TB
subgraph OWASP["OWASP Top 10 2021"]
A1["1. Broken Access Control<br/>(Falha de Controle de Acesso)"]
A2["2. Cryptographic Failures<br/>(Falha de Criptografia)"]
A3["3. Injection<br/>(Injecao)"]
A4["4. Insecure Design<br/>(Design Inseguro)"]
A5["5. Security Misconfiguration<br/>(Configuracao Incorreta)"]
A6["6. Vulnerable Components<br/>(Componentes Vulneraveis)"]
A7["7. Authentication Failures<br/>(Falha de Autenticacao)"]
A8["8. Software Integrity Failures<br/>(Falha de Integridade)"]
A9["9. Logging Failures<br/>(Falha de Log/Monitoramento)"]
A10["10. SSRF<br/>(Server-Side Request Forgery)"]
end
XSS (Cross-Site Scripting)
Tipos de Ataques
flowchart TB
subgraph XSS["Tipos de XSS"]
subgraph Reflected["1. Reflected XSS (Refletido)"]
R1["URL: /search?q=script"] --> R2["HTML: Script inserido nos resultados da busca"]
end
subgraph Stored["2. Stored XSS (Armazenado)"]
S1["Postagem de comentario"] --> S2["Salvo no DB"] --> S3["Exibido para outros usuarios"]
Note1["Codigo de ataque permanece permanentemente"]
end
subgraph DOM["3. DOM-based XSS"]
D1["JS do lado do cliente<br/>insere parametro da URL diretamente no DOM"]
end
end
Medidas de Defesa
// 1. Escape de HTML
function escapeHtml(text: string): string {
const map: Record<string, string> = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
};
return text.replace(/[&<>"']/g, (m) => map[m]);
}
// 2. Usar escape automatico do template engine
// React: JSX faz escape automaticamente
<div>{userInput}</div> // Seguro
// Perigoso: evitar dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{ __html: userInput }} /> // Perigoso!
// 3. Content Security Policy (CSP)
// next.config.js
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: `
default-src 'self';
script-src 'self' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
`.replace(/\n/g, ''),
},
];
// 4. Uso de Cookie HttpOnly
res.cookie('session', token, {
httpOnly: true, // Inacessivel via JavaScript
secure: true, // Requer HTTPS
sameSite: 'strict',
maxAge: 3600000,
});
CSRF (Cross-Site Request Forgery)
sequenceDiagram
participant U as Usuario
participant B as Site do Banco
participant A as Site do Atacante
Note over U,B: 1. Usuario faz login no site legitimo
U->>B: Login
B->>U: Cookie de Sessao
Note over U,A: 2. Acessa site armadilha do atacante
U->>A: Acesso
A->>U: Formulario oculto<br/>(POST para bank.com/transfer)
Note over U,B: 3. Requisicao fraudulenta executada com sessao do usuario
U->>B: POST /transfer<br/>(to=attacker, amount=10000)
B-->>U: Transferencia concluida
Medidas de Defesa
// 1. Token CSRF
import { randomBytes } from 'crypto';
function generateCsrfToken(): string {
return randomBytes(32).toString('hex');
}
// Salvar token na sessao
app.use((req, res, next) => {
if (!req.session.csrfToken) {
req.session.csrfToken = generateCsrfToken();
}
res.locals.csrfToken = req.session.csrfToken;
next();
});
// Incluir token no formulario
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value={csrfToken} />
...
</form>
// Verificacao da requisicao
app.post('/transfer', (req, res) => {
if (req.body._csrf !== req.session.csrfToken) {
return res.status(403).json({ error: 'Invalid CSRF token' });
}
// Executar processamento
});
// 2. SameSite Cookie
res.cookie('session', token, {
sameSite: 'strict', // ou 'lax'
httpOnly: true,
secure: true,
});
// 3. Verificacao do cabecalho Origin
app.use((req, res, next) => {
const origin = req.headers.origin;
const allowedOrigins = ['https://myapp.com'];
if (req.method !== 'GET' && !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
});
SQL Injection
Codigo Vulneravel
// Exemplo perigoso
app.get('/users', async (req, res) => {
const { name } = req.query;
// SQL Injection possivel!
const result = await db.query(`SELECT * FROM users WHERE name = '${name}'`);
res.json(result);
});
// Exemplo de ataque: ?name=' OR '1'='1
// SELECT * FROM users WHERE name = '' OR '1'='1'
// → Todos os usuarios sao obtidos
Medidas de Defesa
// 1. Prepared Statement (consulta parametrizada)
app.get('/users', async (req, res) => {
const { name } = req.query;
const result = await db.query(
'SELECT * FROM users WHERE name = $1',
[name]
);
res.json(result);
});
// 2. Uso de ORM
// Prisma
const users = await prisma.user.findMany({
where: { name },
});
// Drizzle
const users = await db.select().from(usersTable).where(eq(usersTable.name, name));
// 3. Validacao de entrada
import { z } from 'zod';
const QuerySchema = z.object({
name: z.string().max(100).regex(/^[a-zA-Z0-9\s]+$/),
});
app.get('/users', async (req, res) => {
const result = QuerySchema.safeParse(req.query);
if (!result.success) {
return res.status(400).json({ error: 'Invalid input' });
}
// ...
});
Seguranca de Autenticacao
// Hash de senha seguro
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12;
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// Uso seguro de JWT
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET!;
const JWT_EXPIRES_IN = '15m';
const REFRESH_TOKEN_EXPIRES_IN = '7d';
function generateTokens(userId: string) {
const accessToken = jwt.sign({ userId }, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN,
algorithm: 'HS256',
});
const refreshToken = jwt.sign({ userId, type: 'refresh' }, JWT_SECRET, {
expiresIn: REFRESH_TOKEN_EXPIRES_IN,
algorithm: 'HS256',
});
return { accessToken, refreshToken };
}
// Contramedidas para forca bruta
import rateLimit from 'express-rate-limit';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 5, // Ate 5 vezes
message: { error: 'Too many login attempts' },
standardHeaders: true,
legacyHeaders: false,
});
app.post('/login', loginLimiter, async (req, res) => {
// Processamento de login
});
Cabecalhos de Seguranca
// middleware/security.ts
import helmet from 'helmet';
app.use(helmet());
// Ou configuracao individual
app.use((req, res, next) => {
// Filtro XSS
res.setHeader('X-XSS-Protection', '1; mode=block');
// Prevencao de Content-Type sniffing
res.setHeader('X-Content-Type-Options', 'nosniff');
// Prevencao de clickjacking
res.setHeader('X-Frame-Options', 'DENY');
// Forcar HTTPS
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
// Politica de referrer
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
// Politica de permissoes
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
next();
});
Validacao de Entrada
import { z } from 'zod';
import DOMPurify from 'dompurify';
// Definicao de schema
const UserInputSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(2).max(100).regex(/^[\p{L}\s]+$/u),
bio: z.string().max(500).optional(),
website: z.string().url().optional(),
});
// Sanitizacao
function sanitizeHtml(dirty: string): string {
return DOMPurify.sanitize(dirty, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
ALLOWED_ATTR: ['href'],
});
}
// Validacao de upload de arquivo
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
function validateFile(file: File): boolean {
if (file.size > MAX_FILE_SIZE) {
throw new Error('File too large');
}
if (!ALLOWED_TYPES.includes(file.type)) {
throw new Error('Invalid file type');
}
return true;
}
Checklist de Seguranca
| Categoria | Item de Verificacao |
|---|---|
| Autenticacao | Hash de senha (bcrypt/Argon2) |
| Autenticacao | Contramedidas para fixacao de sessao |
| Autenticacao | Suporte a MFA |
| Entrada | Validacao de todas as entradas |
| Entrada | Consulta SQL parametrizada |
| Saida | Escape de HTML |
| Comunicacao | HTTPS obrigatorio |
| Cookie | HttpOnly, Secure, SameSite |
| Cabecalhos | Configuracao CSP, HSTS |
| Dependencias | Verificacao de vulnerabilidades (npm audit) |