Understanding Cross-Site Request Forgery (CSRF) with PHP, MySQL, and Docker
Kathiresan Natarajan
?? Aspiring Cybersecurity Professional | Cloud & Risk Management | Graphic & Logo Design Specialist | Passionate about Innovation, Learning, and Knowledge Sharing | Committed to Securing Digital Assets & Data
Introduction
Cross-Site Request Forgery (CSRF) is a web security vulnerability where an attacker tricks a user into making an unintended request to a web application where they are authenticated. This can lead to unauthorized actions being performed on behalf of the victim.
In this tutorial, we will explore how CSRF attacks work, demonstrate an insecure PHP application vulnerable to CSRF, and implement proper mitigation techniques. We will also deploy our application using Docker.
How CSRF Attacks Work
Analogy: The Fake Check Trick
Imagine you have a signed blank check at home. You trust your roommate to handle your mail but never expect them to misuse your check.
One day, an attacker sends a convincing-looking letter pretending to be from your bank. The letter asks your roommate to fill in an amount and send the check on your behalf. Since your roommate doesn’t know any better, they follow the instructions, thinking it’s legitimate.
What just happened?
How This Relates to CSRF:
Just like how your bank wouldn’t question a signed check, many websites don’t verify if a request was intentionally made by the user—making them vulnerable to CSRF attacks.
Mitigation: Websites should require additional verification (like CSRF tokens) to prevent unauthorized requests—just like a bank should require extra authentication before processing critical transactions.
Setting Up Our Example Application
Requirements
Folder Structure
csfr-demo/
│── docker/
│ ├── Dockerfile
│ ├── docker-compose.yml
│── src/
│ ├── index.php
│ ├── login.php
│ ├── transfer.php (Vulnerable Transfer Endpoint)
│ ├── csrf_protected_transfer.php (Secure Transfer Endpoint)
│ ├── config.php (Database Configuration)
│── attacker/
│ ├── malicious_form.html
│── database/
│ ├── init.sql
Database Setup (MySQL)
Create a MySQL database and user with the following SQL script (init.sql):
CREATE DATABASE csrf_demo;
USE csrf_demo;
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL
);
CREATE TABLE transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
sender VARCHAR(50),
recipient VARCHAR(50),
amount DECIMAL(10,2)
);
Vulnerable PHP Code (Without CSRF Protection)
This is a vulnerable transfer.php file that lacks CSRF protection:
<?php
session_start();
include 'config.php';
if (!isset($_SESSION['user'])) {
die("Unauthorized access");
}
$recipient = $_POST['recipient'];
$amount = $_POST['amount'];
$user = $_SESSION['user'];
$query = $conn->prepare("INSERT INTO transactions (sender, recipient, amount) VALUES (?, ?, ?)");
$query->bind_param("ssd", $user, $recipient, $amount);
$query->execute();
echo "Transfer successful";
?>
Problem:
How an Attacker Exploits CSRF
The attacker creates a fake page (malicious_form.html) that tricks the victim into unknowingly transferring money.
<!DOCTYPE html>
<html>
<head>
<title>Claim Your Prize</title>
</head>
<body>
<h1>Congratulations! You've Won!</h1>
<form action="https://localhost:8080/transfer.php" method="POST">
<input type="hidden" name="recipient" value="attacker">
<input type="hidden" name="amount" value="1000">
<input type="submit" value="Claim Now">
</form>
</body>
</html>
Delivery Method:
How the Victim Gets Tricked
领英推荐
Secure PHP Code (With CSRF Protection)
Modify csrf_protected_transfer.php to use CSRF tokens:
<?php
session_start();
include 'config.php';
if (!isset($_SESSION['user']) || !isset($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die("Invalid CSRF Token");
}
$recipient = $_POST['recipient'];
$amount = $_POST['amount'];
$user = $_SESSION['user'];
$query = $conn->prepare("INSERT INTO transactions (sender, recipient, amount) VALUES (?, ?, ?)");
$query->bind_param("ssd", $user, $recipient, $amount);
$query->execute();
echo "Transfer successful";
?>
Secure index.php (Generating CSRF Token)
<?php
session_start();
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
?>
<form action="csrf_protected_transfer.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
<input type="text" name="recipient" placeholder="Recipient">
<input type="number" name="amount" placeholder="Amount">
<input type="submit" value="Transfer">
</form>
Building & Deploying with Docker
Dockerfile:
FROM php:apache
COPY src/ /var/www/html/
RUN docker-php-ext-install mysqli
EXPOSE 80
docker-compose.yml:
version: '3'
services:
web:
build: .
ports:
- "8080:80"
depends_on:
- db
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: csrf_demo
volumes:
- ./database/init.sql:/docker-entrypoint-initdb.d/init.sql
Running the Project:
Final Thoughts & Prevention Techniques
Preventing CSRF Attacks:
? Use CSRF tokens for form submissions.
? Implement SameSite cookies in session management.
? Validate HTTP Referer & Origin headers.
? Educate users on phishing threats.
? Implement multi-factor authentication (MFA) for sensitive actions.
By following these steps, you can protect your web applications from CSRF attacks. Stay secure! ??