0

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):

  1. A01: Broken Access Control — Users can act outside their intended permissions. IDOR, privilege escalation, missing authorization.
  2. A02: Cryptographic Failures — Weak or missing encryption. Passwords in plaintext, MD5 for passwords, weak TLS.
  3. A03: Injection — SQL injection, LDAP injection, command injection. Untrusted data sent to an interpreter.
  4. A04: Insecure Design — Missing security controls at the design level. No threat modeling, no defense-in-depth.
  5. A05: Security Misconfiguration — Default credentials, verbose error messages in production, unnecessary features enabled.
  6. A06: Vulnerable and Outdated Components — Using libraries with known CVEs.
  7. A07: Identification and Authentication Failures — Weak passwords allowed, no brute-force protection, broken session management.
  8. A08: Software and Data Integrity Failures — Untrusted deserialization, unsigned updates, CI/CD pipeline without integrity checks.
  9. A09: Security Logging and Monitoring Failures — Not logging security events, not detecting breaches, no alerting.
  10. 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!