Every web application, regardless of framework or language, faces security risks that can compromise data, users, and reputation. The OWASP Top 10 is the most authoritative reference for identifying and mitigating critical vulnerabilities. This guide analyzes each of the ten risk categories, providing concrete examples in plain PHP and the Laravel framework. The goal is to turn awareness into action with secure code and ready-to-use best practices.
What is the OWASP Top 10 and why it still matters
The Open Web Application Security Project periodically publishes a list of the ten most widespread and dangerous vulnerabilities for web applications. This document is the starting point for any application security program. Ignoring these categories is like leaving the door open to data breaches, code injections, and identity theft. For a PHP and Laravel developer, knowing and preventing these risks is a professional duty.
Guide structure
For each vulnerability we provide: a brief description of the risk, a vulnerable example in plain PHP, the corrected secure version, and finally the Laravel counterpart (when applicable).
A01:2025 – Broken Access Control
Broken access control occurs when a user can perform actions or view data outside their permissions. It is the most common vulnerability.
Vulnerable example in PHP
<?php
// profile.php?id=5
$userId = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$userId]);
$user = $stmt->fetch();
// No check: any user can see anyone else's data
Fix in PHP
<?php
session_start();
$currentUserId = $_SESSION['user_id'];
$requestedUserId = (int) $_GET['id'];
if ($requestedUserId !== $currentUserId && !in_array('admin', $_SESSION['roles'])) {
http_response_code(403);
exit('Access denied');
}
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$requestedUserId]);
$user = $stmt->fetch();
Laravel: Policies and Gates
// App\Policies\UserPolicy
public function view(User $authenticatedUser, User $targetUser)
{
return $authenticatedUser->id === $targetUser->id
|| $authenticatedUser->hasRole('admin');
}
// In the controller
public function show(User $user)
{
$this->authorize('view', $user);
return view('users.show', compact('user'));
}
A02:2025 – Cryptographic Failures
Insufficient protection of sensitive data in transit and at rest. Includes weak algorithms, hardcoded keys, and unencrypted transmissions.
Vulnerable example in PHP
// Storing passwords with MD5
$hashed = md5($password); // Absolutely avoid
Modern solution
$hashed = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
$verified = password_verify($inputPassword, $storedHash);
Laravel: automatic encryption
Laravel uses bcrypt by default for passwords and provides the Crypt facade to encrypt sensitive data with AES-256.
use Illuminate\Support\Facades\Crypt;
$encrypted = Crypt::encryptString('sensitive data');
$decrypted = Crypt::decryptString($encrypted);
A03:2025 – Injection
Injection attacks (SQL, NoSQL, OS Command, LDAP) occur when untrusted data is sent to an interpreter as part of a command. It is one of the oldest and still widespread vulnerabilities.
Vulnerable example in PHP
$query = "SELECT * FROM products WHERE id = " . $_GET['id'];
$result = mysqli_query($conn, $query);
Fix with Prepared Statements
$stmt = $pdo->prepare("SELECT * FROM products WHERE id = ?");
$stmt->execute([$_GET['id']]);
Laravel Eloquent and Query Builder
// Eloquent (ORM) – protected by default
$product = Product::find($request->id);
// Query Builder – bound parameters
$products = DB::table('products')->where('id', $request->id)->get();
A04:2025 – Insecure Design
Concerns architectural mistakes that make the application vulnerable even before writing code. Examples: lack of rate limiting, trusting client-side data, unsafe business logic.
Example in PHP
// Price comes from a hidden form field – trusting is dangerous
$price = $_POST['price_hidden'];
Solution: server-side validation
$correctPrice = calculatePriceFromDatabase($productId);
if ($submittedPrice !== $correctPrice) {
// Reject
}
Laravel: Form Request + Policy
Use Form Request to validate input and Policy to authorize actions.
A05:2025 – Security Misconfiguration
Incorrect configuration at server, framework, library, or cloud level. Includes default permissions, enabled directory listing, exposed stack traces.
Example in Laravel
Not removing APP_DEBUG=true in production exposes detailed errors.
// .env in production
APP_DEBUG=false
General best practices
- Disable directory listing in web server (Apache:
Options -Indexes; Nginx:autoindex off;) - Enforce HTTPS
- Keep framework and libraries updated
A06:2025 – Vulnerable and Outdated Components
Using packages with known vulnerabilities. Tools like composer audit and Dependabot help detect them.
Check in Laravel
composer audit
Integrate Dependabot on GitHub for automatic updates.
A07:2025 – Identification and Authentication Failures
Weak authentication mechanisms: predictable sessions, missing MFA, insufficient password policies.
Vulnerable example in PHP
session_start();
if (!isset($_SESSION['user_id'])) {
// bypassable login?
}
Laravel: robust authentication
Laravel implements multiple guards, rate limiting on logins, and natively supports multi-factor authentication with packages like larage.
// config/auth.php – already secure by default
'password' => ['min:8', 'mixedCase', 'symbols'],
A08:2025 – Software and Data Integrity Failures
Lack of verification of software or data integrity. Includes unsigned updates, unverified dependencies, insecure CI/CD.
Example: malicious Composer packages
Verify signatures in composer.lock and use only trusted repositories.
Laravel: package signing
Use composer verify and enable secure-by-default for first-party packages.
A09:2025 – Security Logging and Monitoring Failures
Lack of sufficient logging to detect ongoing attacks – an attack without traces is invisible.
Implementation in Laravel
// In a middleware
Log::warning('Unauthorized access attempt', ['user' => $user->id, 'ip' => $request->ip()]);
Configure alerting on Slack, email, or tools like Sentry.
A10:2025 – Server-Side Request Forgery (SSRF)
SSRF allows an attacker to force the server to make requests to internal resources, such as cloud metadata or internal services.
Vulnerable example in PHP
$url = $_GET['url'];
$content = file_get_contents($url);
Mitigation in Laravel
Validate and whitelist URLs, use Http::fake() in tests, and restrict allowed protocols.
use Illuminate\Support\Facades\Http;
$response = Http::timeout(5)->get('https://api.example.com');
Conclusion and best practices
Security is not an option but a fundamental requirement. Integrating the defenses described in this guide drastically reduces the risk of incidents. Here are concrete steps to follow:
- Adopt the OWASP ASVS (Application Security Verification Standard) as a checklist.
- Run automated scanners like Wapiti or Burp Suite.
- Train the team with periodic secure coding sessions.
- Keep dependencies and the framework updated.
- Integrate automated security tests into the CI/CD pipeline.
For a broader view of web application security, check the Definitive Cybersecurity Guide for Web Developers.
Authoritative external resource: Official OWASP Top 10.
Sponsored Protocol