DEV Community

Eko Priyanto
Eko Priyanto

Posted on • Edited on

PHP security checklist

https://freedium.cfd/https://levelup.gitconnected.com/secure-your-php-code-8cd5921047a0

Security is crucial when developing with PHP, as poorly written code can expose vulnerabilities such as SQL injection, XSS (Cross-Site Scripting), and CSRF (Cross-Site Request Forgery). Below are best practices and secure code examples.

Validate and Sanitize User Input
User input should never be trusted. Always validate and sanitize input before using it.

✅ Example: Sanitizing User Input

Copy

<?php
// Using filter_input() to sanitize user input
$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_STRING);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);

if (!$email) {
    echo "Invalid email!";
} else {
    echo "Hello, " . htmlspecialchars($name);
}
?>
Enter fullscreen mode Exit fullscreen mode

FILTER_SANITIZE_STRING: Removes harmful characters from strings.
FILTER_VALIDATE_EMAIL: Ensures the email is valid.
htmlspecialchars(): Prevents XSS attacks by escaping special characters.
Use Prepared Statements to Prevent SQL Injection
SQL Injection happens when user input is directly used in an SQL query. Always use prepared statements.

❌ Insecure SQL Query (Vulnerable to SQL Injection)

Copy

<?php
$conn = new mysqli("localhost", "user", "password", "database");
$user_input = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = '$user_input'"; // 🚨 Unsafe: User can manipulate the query!
$result = $conn->query($sql);
?>
Enter fullscreen mode Exit fullscreen mode

A hacker can enter: 1' OR '1'='1 This makes the query return all users instead of just one.

✅ Secure SQL Query (Using Prepared Statements)

Copy

<?php
$conn = new mysqli("localhost", "user", "password", "database");
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']); // "i" stands for integer
$stmt->execute();
$result = $stmt->get_result();
?> 
Enter fullscreen mode Exit fullscreen mode

Prevents SQL injection by binding user input.
Used "i" to indicate that it id is an integer.
Secure Password Handling
Never store passwords in plain text. Always hash passwords before saving them.

✅ Hash a Password Before Storing

Copy

<?php
$password = "my_secure_password";
$hashed_password = password_hash($password, PASSWORD_BCRYPT);
echo $hashed_password; // Store this in the database
?>
Enter fullscreen mode Exit fullscreen mode

PASSWORD_BCRYPT generates a strong, salted hash.
✅ Verify Password During Login

Copy

<?php
$entered_password = "my_secure_password";
$stored_hash = '$2y$10$Qj4X...'; // Retrieved from the database

if (password_verify($entered_password, $stored_hash)) {
    echo "Login successful!";
} else {
    echo "Invalid password!";
}
?>
Enter fullscreen mode Exit fullscreen mode

password_verify() compares user input with the stored hash.
Protect Against Cross-Site Scripting (XSS)
XSS occurs when malicious scripts are injected into web pages. To prevent XSS:

✅ Escape Output Using htmlspecialchars()

Copy

<?php
$comment = $_POST['comment'];
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8'); // Prevents JavaScript execution
?>
Enter fullscreen mode Exit fullscreen mode

If a user inputs:alert(&#39;Hacked!&#39;); Without htmlspecialchars(), it would execute as JavaScript!

Prevent Cross-Site Request Forgery (CSRF)
CSRF happens when malicious websites trick users into performing unwanted actions. Use CSRF tokens.

✅ Generate and Validate a CSRF Token

<?php
session_start();
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
?>
Enter fullscreen mode Exit fullscreen mode
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
        die("CSRF validation failed!");
    }
    echo "Form submitted successfully!";
}
?> 
Enter fullscreen mode Exit fullscreen mode

The hidden input field sends the token.
hash_equals() ensures the token matches.
Disable Error Display in Production
Errors can expose sensitive information. Always log errors instead of displaying them.

✅ Turn Off the Error Display in php.ini

Copy
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
✅ Manually Log Errors

<?php
error_log("Something went wrong!", 3, "/var/log/php_errors.log");
?>
Enter fullscreen mode Exit fullscreen mode

Secure File Uploads
If your site allows file uploads, validate and store file types securely.

✅ Check File Type Before Uploading

Copy

<?php
$allowed_types = ['image/jpeg', 'image/png'];
if (!in_array($_FILES['file']['type'], $allowed_types)) {
    die("Invalid file type!");
}
?>
Enter fullscreen mode Exit fullscreen mode

Avoid storing uploads in a web-accessible directory to prevent direct access.

Restrict PHP Execution in Uploads
Prevent attackers from executing PHP files in the upload folder by disabling PHP execution with a .htaccess file.

✅ Block PHP Execution in Uploads

Copy

Deny from all

Use Secure Headers
Set HTTP headers to enhance security.

✅ Enable Secure Headers

Copy

<?php
header("X-Frame-Options: DENY"); // Prevents clickjacking
header("X-XSS-Protection: 1; mode=block"); // Prevents XSS
header("X-Content-Type-Options: nosniff"); // Prevents MIME-type sniffing
?>
Enter fullscreen mode Exit fullscreen mode

Final Thoughts
By following these best security practices, you can protect your PHP applications from common threats. 🚀

Top comments (0)