OWASP Top 10 — the 10 most critical web application security risks
Intermediate5 min read·eng-19-010
interviewsecurity
Concept
OWASP Top 10 — a list maintained by the Open Web Application Security Project of the 10 most critical web application security risks. Updated periodically, widely used as a minimum security checklist.
OWASP Top 10 (2021 edition):
- A01: Broken Access Control — Users can act outside their intended permissions. IDOR, privilege escalation, missing authorization.
- A02: Cryptographic Failures — Weak or missing encryption. Passwords in plaintext, MD5 for passwords, weak TLS.
- A03: Injection — SQL injection, LDAP injection, command injection. Untrusted data sent to an interpreter.
- A04: Insecure Design — Missing security controls at the design level. No threat modeling, no defense-in-depth.
- A05: Security Misconfiguration — Default credentials, verbose error messages in production, unnecessary features enabled.
- A06: Vulnerable and Outdated Components — Using libraries with known CVEs.
- A07: Identification and Authentication Failures — Weak passwords allowed, no brute-force protection, broken session management.
- A08: Software and Data Integrity Failures — Untrusted deserialization, unsigned updates, CI/CD pipeline without integrity checks.
- A09: Security Logging and Monitoring Failures — Not logging security events, not detecting breaches, no alerting.
- A10: Server-Side Request Forgery (SSRF) — Server fetches a URL provided by an attacker, allowing access to internal services.
Using OWASP Top 10: Use it as a review checklist during development. Each new feature should be reviewed against these categories.
Code Example
php
<?php
// OWASP TOP 10 — quick reference in Laravel context
// A01: Broken Access Control — always check ownership
Route::get('/orders/{order}', function (Order $order) {
// WRONG: just auth check
// return $order;
// RIGHT: check user owns this order
if ($order->user_id !== auth()->id()) abort(403);
return $order;
});
// A02: Cryptographic Failures — use bcrypt/argon2, not MD5
// WRONG: Hash::make($password, 'sha256')
// RIGHT: Hash::make($password) // bcrypt by default
// A03: Injection — use parameterized queries
// WRONG: DB::select("SELECT * FROM users WHERE id = $id")
// RIGHT: User::find($id) or DB::table('users')->where('id', $id)->first()
// A05: Security Misconfiguration — disable debug in production
// .env: APP_DEBUG=false in production
// Don't expose stack traces: return response()->json(['message' => 'Server Error'], 500);
// A06: Outdated components
// composer audit ← check for known vulnerabilities
// npm audit
// A07: Authentication Failures — throttle login attempts
// Laravel has built-in throttle middleware
Route::post('/login', [AuthController::class, 'login'])->middleware('throttle:5,1');
// Max 5 attempts per minute per IP
// A08: Integrity — validate webhook signatures
Route::post('/webhooks/github', function (Request $request) {
$expected = 'sha256=' . hash_hmac('sha256', $request->getContent(), config('services.github.secret'));
if (!hash_equals($expected, $request->header('X-Hub-Signature-256'))) {
abort(401);
}
});
// A09: Logging — log security events
// Log failed login attempts, permission denials, suspicious input
Log::warning('Failed login attempt', ['email' => $request->email, 'ip' => $request->ip()]);
// A10: SSRF — validate/restrict URLs your app fetches
function fetchUrl(string $url): Response
{
$parsed = parse_url($url);
$allowedHosts = ['api.github.com', 'api.stripe.com'];
if (!in_array($parsed['host'], $allowedHosts)) {
throw new \InvalidArgumentException("Unauthorized URL: {$url}");
}
return Http::get($url);
}
// Without this check: fetchUrl('http://169.254.169.254/latest/meta-data/')
// → reads AWS EC2 instance metadata including IAM credentials!