OWASP Top 10: Las Amenazas Más Críticas
El OWASP Top 10 es el estándar de facto para seguridad de aplicaciones web. Esta lista identifica las 10 vulnerabilidades más críticas que todo desarrollador debe conocer y prevenir.
En esta guía analizamos cada vulnerabilidad y cómo proteger tu aplicación Laravel contra ellas.
¿Qué es OWASP?
OWASP (Open Web Application Security Project) es una fundación sin fines de lucro dedicada a mejorar la seguridad del software. Su Top 10 se actualiza cada 3-4 años basándose en datos reales de vulnerabilidades.
Por Qué Importa
- 43% de las brechas de datos afectan a pequeñas empresas
- El costo promedio de un data breach es $4.24 millones USD
- 95% de las vulnerabilidades web caen en el OWASP Top 10
- Cumplimiento normativo (GDPR, PDPA Argentina) lo requiere
OWASP Top 10 (2021) Explicado
1. Broken Access Control
Qué es: Usuarios accediendo a recursos que no deberían (ej: datos de otros usuarios)
Ejemplo de Vulnerabilidad
// ❌ VULNERABLE: No valida si el usuario tiene permiso
Route::get('/invoice/{id}', function($id) {
$invoice = Invoice::find($id);
return view('invoice', compact('invoice'));
});
Ataque: Usuario modifica URL de /invoice/123 a /invoice/124 y ve factura de otro cliente.
Solución en Laravel
// ✅ SEGURO: Valida ownership
Route::get('/invoice/{id}', function($id) {
$invoice = Invoice::where('id', $id)
->where('user_id', auth()->id())
->firstOrFail();
return view('invoice', compact('invoice'));
});
// O mejor aún, usa Policies
Route::get('/invoice/{invoice}', function(Invoice $invoice) {
$this->authorize('view', $invoice);
return view('invoice', compact('invoice'));
});
// InvoicePolicy.php
public function view(User $user, Invoice $invoice)
{
return $user->id === $invoice->user_id;
}
2. Cryptographic Failures
Qué es: Datos sensibles expuestos por falta o mala implementación de encriptación
Ejemplo de Vulnerabilidad
// ❌ VULNERABLE: Almacenar tarjeta de crédito en texto plano
DB::table('payments')->insert([
'user_id' => $user->id,
'credit_card' => $request->credit_card, // ¡Nunca hagas esto!
]);
Solución en Laravel
// ✅ SEGURO: Usar encriptación de Laravel
use Illuminate\Support\Facades\Crypt;
// Almacenar
DB::table('sensitive_data')->insert([
'user_id' => $user->id,
'data' => Crypt::encryptString($sensitiveData),
]);
// Recuperar
$decrypted = Crypt::decryptString($encrypted);
// Para datos que deben ser buscables, usar hashing
$hashed = Hash::make($password);
Hash::check($plainText, $hashed); // Verificar
Mejores prácticas:
- Nunca almacenar tarjetas de crédito (usar Stripe, MercadoPago)
- Usar HTTPS en producción (certificado SSL)
- Encriptar datos sensibles en DB
- Hash de passwords con Bcrypt (Laravel lo hace por defecto)
3. Injection (SQL Injection, XSS, etc.)
Qué es: Insertar código malicioso en queries, comandos o scripts
SQL Injection
// ❌ VULNERABLE: Concatenación directa
$email = $request->email;
$user = DB::select("SELECT * FROM users WHERE email = '$email'");
// Ataque: $email = "' OR 1=1 --"
// Query resultante: SELECT * FROM users WHERE email = '' OR 1=1 --'
// Devuelve TODOS los usuarios
// ✅ SEGURO: Usar Eloquent o Query Builder
$user = User::where('email', $request->email)->first();
// O con bindings
$users = DB::select('SELECT * FROM users WHERE email = ?', [$request->email]);
XSS (Cross-Site Scripting)
// ❌ VULNERABLE: Imprimir input sin escapar
<div>{{ $user->bio }}</div> // Si bio tiene <script>, se ejecuta
// ✅ SEGURO: Blade escapa por defecto
{{ $user->bio }} // Escapado automáticamente
// Para HTML confiable, usa {!! !!} con extremo cuidado
{!! Purifier::clean($user->bio) !!} // Usa HTMLPurifier
4. Insecure Design
Qué es: Fallas de diseño arquitectural, no bugs de implementación
Ejemplos
- No rate limiting: API permite 1000 requests/segundo = DoS fácil
- Recuperación de password insegura: "¿Cuál es el nombre de tu mascota?"
- No CAPTCHA en registro: Bots crean miles de cuentas
Solución en Laravel
// Rate Limiting
Route::middleware('throttle:60,1')->group(function () {
Route::post('/api/endpoint', [Controller::class, 'method']);
});
// CAPTCHA (Google reCAPTCHA v3)
// En ContactController (ya implementado en el proyecto)
$recaptchaToken = $request->input('recaptcha_token');
$response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
'secret' => config('services.recaptcha.secret'),
'response' => $recaptchaToken,
]);
if (!$response->json()['success'] || $response->json()['score'] < 0.5) {
return back()->withErrors(['message' => 'Verificación de seguridad falló']);
}
5. Security Misconfiguration
Qué es: Configuraciones inseguras o por defecto
Errores Comunes
| Error | Riesgo | Solución |
|---|---|---|
| Debug mode en producción | Expone rutas de archivos, DB | APP_DEBUG=false en .env |
| Listado de directorios habilitado | Ver archivos del servidor | Options -Indexes en .htaccess |
| Headers de seguridad faltantes | XSS, clickjacking | Middleware de headers |
| Versiones antiguas de PHP/Laravel | Vulnerabilidades conocidas | Actualizar regularmente |
Headers de Seguridad (Middleware)
// app/Http/Middleware/SecurityHeaders.php
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
$response->headers->set('Content-Security-Policy', "default-src 'self'");
return $response;
}
6. Vulnerable and Outdated Components
Qué es: Usar librerías con vulnerabilidades conocidas
Prevención
# Auditar dependencias regularmente
composer audit
# Actualizar dependencias
composer update
# En package.json
npm audit
npm audit fix
Monitoreo automático:
- GitHub Dependabot (alertas automáticas)
- Snyk.io (escaneo de vulnerabilidades)
- Renovate Bot (PRs automáticos para updates)
7. Identification and Authentication Failures
Qué es: Fallas en autenticación y gestión de sesiones
Ejemplo: Brute Force Attack
// ✅ Laravel incluye rate limiting en login
// En LoginController
use Illuminate\Foundation\Auth\ThrottlesLogins;
protected $maxAttempts = 5; // 5 intentos
protected $decayMinutes = 15; // Bloqueo de 15 minutos
2FA (Two-Factor Authentication)
// Instalar Laravel Fortify
composer require laravel/fortify
// Habilitar 2FA
// config/fortify.php
'features' => [
Features::twoFactorAuthentication([
'confirm' => true,
'confirmPassword' => true,
]),
],
8. Software and Data Integrity Failures
Qué es: Código o infraestructura que confía en fuentes no verificadas
Ejemplo: Dependency Confusion
// ❌ VULNERABLE: Instalar paquetes sin verificar
composer require paquete-random
// ✅ SEGURO: Verificar source y reputación
// - Revisar downloads en Packagist
// - Ver actividad en GitHub
// - Leer código antes de usar
// - Usar lock files (composer.lock, package-lock.json)
9. Security Logging and Monitoring Failures
Qué es: No detectar, alertar o responder a brechas
Logging Correcto
// Loguear eventos de seguridad
Log::warning('Failed login attempt', [
'email' => $request->email,
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
]);
Log::critical('Unauthorized access attempt', [
'user_id' => auth()->id(),
'resource' => $request->url(),
]);
Herramientas de monitoreo:
- Laravel Telescope (desarrollo)
- Sentry.io (errores en producción)
- LogRocket (session replay)
- Fail2Ban (bloqueo automático de IPs)
10. Server-Side Request Forgery (SSRF)
Qué es: Engañar al servidor para que haga requests no autorizados
Ejemplo de Vulnerabilidad
// ❌ VULNERABLE: Fetch URL del usuario sin validar
$url = $request->input('url');
$content = file_get_contents($url);
// Ataque: $url = "file:///etc/passwd" o "http://localhost/admin"
Solución
// ✅ SEGURO: Validar y sanitizar URLs
$url = $request->input('url');
// Validar esquema
if (!str_starts_with($url, 'https://')) {
abort(400, 'Only HTTPS allowed');
}
// Whitelist de dominios
$allowedDomains = ['api.example.com', 'cdn.example.com'];
$domain = parse_url($url, PHP_URL_HOST);
if (!in_array($domain, $allowedDomains)) {
abort(403, 'Domain not allowed');
}
// Usar HTTP client de Laravel con timeout
$response = Http::timeout(5)->get($url);
Checklist de Seguridad para Laravel
Configuración (.env)
- ☐
APP_DEBUG=falseen producción - ☐
APP_KEYgenerado y secreto - ☐
APP_URLcon HTTPS - ☐ Credenciales DB no por defecto
Código
- ☐ Usar Eloquent/Query Builder (no raw SQL)
- ☐ Validar TODOS los inputs (
$request->validate()) - ☐ Sanitizar outputs (
{{ }}en Blade) - ☐ CSRF protection habilitado (
@csrfen forms) - ☐ Policies para authorization
- ☐ Rate limiting en APIs y forms
Infraestructura
- ☐ SSL/TLS certificado válido
- ☐ Firewall configurado
- ☐ SSH con keys (no passwords)
- ☐ Backups automáticos
- ☐ PHP y dependencias actualizadas
Herramientas de Testing de Seguridad
| Herramienta | Qué Detecta | Costo |
|---|---|---|
| OWASP ZAP | Vulnerabilidades web automáticas | Gratis |
| Burp Suite | Penetration testing completo | Gratis / $399/año Pro |
| Snyk | Vulnerabilidades en dependencias | Gratis / Planes pagos |
| SonarQube | Code quality + seguridad | Gratis / Enterprise |
Conclusión
La seguridad no es opcional. Una brecha puede:
- 💸 Costar millones en multas y remediación
- 😰 Destruir la confianza de tus clientes
- ⚖️ Resultar en consecuencias legales
- 📉 Arruinar la reputación de tu marca
La buena noticia: Laravel incluye protecciones por defecto contra la mayoría del OWASP Top 10. Pero debes usarlas correctamente.
En SofihaCloud desarrollamos aplicaciones con security-first approach:
- 🔒 Auditorías de seguridad incluidas
- ✅ Cumplimiento OWASP Top 10
- 🛡️ Penetration testing antes de producción
- 📊 Monitoreo y logging robustos
- 🔄 Actualizaciones de seguridad proactivas
¿Tu aplicación está protegida?
📞 Contactanos para una auditoría de seguridad gratuita.