Content Available in Spanish Only
This article is currently available only in Spanish. We're working on translations.
Available in: ES • Tip: Use your browser's translation feature or visit the Spanish version
¿Qué es el OWASP Cheat Sheet Series?
El OWASP Cheat Sheet Series es una colección de más de 80 guías de referencia rápida, cada una centrada en un tema de seguridad específico. Están diseñadas para que los desarrolladores implementen controles de seguridad correctamente, sin necesidad de convertirse en expertos en seguridad.
Cada cheat sheet tiene el mismo formato: contexto del problema, controls específicos con ejemplos de código, qué evitar y referencias. Son el complemento perfecto del OWASP Top 10: el Top 10 te dice qué puede salir mal, los Cheat Sheets te dicen exactamente cómo implementarlo bien.
¿Cómo usarlos en el día a día?
Los Cheat Sheets más importantes
Autenticación y gestión de sesiones
import bcrypt from 'bcrypt';
// Almacenamiento (registro)
const SALT_ROUNDS = 12; // work factor recomendado para 2025
const hashedPassword = await bcrypt.hash(plainPassword, SALT_ROUNDS);
// → almacenar hashedPassword en BD, nunca plainPassword
// Verificación (login)
const isValid = await bcrypt.compare(inputPassword, storedHash);
// → bcrypt ya maneja timing-safe comparison internamente
// ❌ NUNCA usar:
// MD5, SHA1, SHA256 directos (sin salt, sin work factor → crackeable con GPU)
// crypto.createHash('md5').update(pass).digest('hex')Prevención de inyecciones
// HTML Context — escapar entidades HTML
function escapeHtml(str: string): string {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// DOM Context — usar DOMPurify para HTML enriquecido
import DOMPurify from 'dompurify';
const cleanHtml = DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong'],
ALLOWED_ATTR: []
});
// JavaScript Context — nunca interpolar directamente
// Ejemplo: const js = JSON.stringify({ user: userName });
// ✅ Usar JSON.stringify() para datos en scripts
const safeData = JSON.stringify({ user: userName });
const js = 'var user = ' + safeData + ';';
// URL Context — encodeURIComponent para parámetros
const url = '/search?q=' + encodeURIComponent(userQuery);Criptografía y datos sensibles
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
const ALGORITHM = 'aes-256-gcm'; // ✅ modo autenticado
function encrypt(plaintext: string, key: Buffer): { iv: string; tag: string; data: string } {
const iv = randomBytes(12); // 96 bits para GCM
const cipher = createCipheriv(ALGORITHM, key, iv);
const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag(); // authentication tag de GCM
return {
iv: iv.toString('hex'),
tag: tag.toString('hex'),
data: encrypted.toString('hex')
};
}
function decrypt(encrypted: { iv: string; tag: string; data: string }, key: Buffer): string {
const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(encrypted.iv, 'hex'));
decipher.setAuthTag(Buffer.from(encrypted.tag, 'hex'));
return Buffer.concat([
decipher.update(Buffer.from(encrypted.data, 'hex')),
decipher.final()
]).toString('utf8');
}Cabeceras HTTP de seguridad
// next.config.ts — cabeceras de seguridad recomendadas por OWASP
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload' // HSTS 2 años
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN' // Clickjacking protection
},
{
key: 'X-Content-Type-Options',
value: 'nosniff' // MIME sniffing protection
},
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
},
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'nonce-{nonce}'; ..."
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()'
}
];Infraestructura y DevSecOps
# ❌ Imagen insegura
FROM node:latest
COPY . /app
RUN npm install
CMD ["node", "server.js"]
# ✅ Imagen segura siguiendo Docker Security CS
FROM node:22-alpine AS builder # imagen mínima, no 'latest'
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production # solo dependencias de producción
FROM node:22-alpine AS runner
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --chown=appuser:appgroup . .
USER appuser # no-root
EXPOSE 3000
CMD ["node", "server.js"]