An OWASP Top 10 Checklist for PHP Developers
A practical, no-fluff checklist for catching the most common security issues in PHP web applications — based on real code review findings.
Most PHP security problems aren't exotic. They're the same handful of issues showing up in codebases over and over again. The OWASP Top 10 is a good framework for thinking about them systematically. Here's how each one translates to concrete PHP code.
1. Injection — SQL, Command, LDAP
The classic. Never concatenate user input directly into a query.
// NEVER do this
$result = mysqli_query($conn, "SELECT * FROM users WHERE id = " . $_GET['id']);
// Use prepared statements
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
Checklist: Every database query uses prepared statements or a query builder. No raw $_GET, $_POST, or $_COOKIE values concatenated into SQL strings.
2. Broken Authentication
Weak session handling is where most PHP apps fall down. Key things to check:
- Call
session_regenerate_id(true)on login - Use
password_hash()andpassword_verify()— never MD5 or SHA1 - Set session cookies with
HttpOnlyandSecureflags - Enforce a session timeout and destroy sessions on logout
// Harden session cookies
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true, // HTTPS only
'httponly' => true, // No JS access
'samesite' => 'Strict', // CSRF mitigation
]);
session_start();
session_regenerate_id(true);
3. Cross-Site Scripting (XSS)
Any time you output user-supplied data in HTML, escape it. Every time. No exceptions.
// Bad — outputs raw user input
echo $_GET['name'];
// Good — escape for HTML context
echo htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');
// Convenience wrapper
function e(string $s): string {
return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}
echo e($_GET['name']);
Note: strip_tags() is not a substitute for htmlspecialchars(). It removes tags but doesn't neutralize attributes like onerror or onclick on allowed tags.
4. Insecure File Uploads
File uploads are one of the highest-risk features in any PHP application. The checklist here is longer:
- Validate MIME type server-side using
finfo, not$_FILES['type'](that's user-controlled) - Enforce an allowlist of file extensions — deny everything not on it
- Store uploads outside the document root, or in a directory with PHP execution disabled
- Rename uploaded files to a random name — never use the original filename
- Scan with ClamAV for malware before storing
- Set a maximum file size both in PHP config and application logic
This is a living checklist — I'll keep adding to it. If you want a proper security review of your PHP application, get in touch.