================================================================================ EXERCISE 4.2: CSRF ATTACK - COMPLETE CODE Siddesh Vilas Pawar | MSc Cyber Security University of Surrey | COMM047 ================================================================================ This file contains ALL code files needed for the CSRF demonstration. Copy each section into the respective file as indicated. DIRECTORY STRUCTURE: csrf_demo/ ├── README.md (see Exercise4_Web_Security.html) ├── vulnerable/ (6 files below) ├── attacker/ (1 file below) └── secure/ (6 files below) ================================================================================ VULNERABLE VERSION - Files 1-6 ================================================================================ ================================================================================ FILE 1: vulnerable/init_db.php ================================================================================ setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Create users table with names and password for login access, then balance $db->exec(" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, balance REAL NOT NULL DEFAULT 0 ) "); // Create transactions table for convo $db->exec(" CREATE TABLE IF NOT EXISTS transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT NOT NULL, recipient TEXT NOT NULL, amount REAL NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) "); // Clear existing data like users and transactions $db->exec("DELETE FROM users"); $db->exec("DELETE FROM transactions"); // Insert test users (plaintext passwords for demo only!) $users = [ ['alice', 'alice123', 5000], ['bob', 'bob123', 3000], ['eve', 'eve123', 1000] ]; $stmt = $db->prepare("INSERT INTO users (username, password, balance) VALUES (?, ?, ?)"); foreach ($users as $user) { $stmt->execute($user); } echo "✓ Database initialized successfully!\n"; echo "Test users created:\n"; echo " alice/alice123 - \$5,000\n"; echo " bob/bob123 - \$3,000\n"; echo " eve/eve123 - \$1,000\n"; } catch (PDOException $e) { die("✗ Database error: " . $e->getMessage()); } ?> ================================================================================ FILE 2: vulnerable/index.php ================================================================================ prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->execute([$username, $password]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { $_SESSION['user'] = $username; header('Location: dashboard.php'); exit; } else { $error = 'Invalid credentials'; } } catch (PDOException $e) { $error = 'Database error'; } } ?> Vulnerable Bank - Login

🏦 Vulnerable Bank Login

NO CSRF PROTECTION

Test users: alice/alice123, bob/bob123, eve/eve123

================================================================================ FILE 3: vulnerable/dashboard.php ================================================================================ prepare("SELECT balance FROM users WHERE username = ?"); $stmt->execute([$username]); $balance = $stmt->fetchColumn(); $stmt = $db->prepare(" SELECT * FROM transactions WHERE sender = ? OR recipient = ? ORDER BY timestamp DESC LIMIT 10 "); $stmt->execute([$username, $username]); $transactions = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { die('Database error'); } ?> Dashboard - Vulnerable Bank

Welcome,

Current Balance: $
VULNERABLE: No CSRF protection on transfer form!

Transfer Money

Recent Transactions

FromToAmountTime
$
Logout
================================================================================ FILE 4: vulnerable/transfer.php ( VULNERABLE!) ================================================================================ beginTransaction(); $stmt = $db->prepare("SELECT balance FROM users WHERE username = ?"); $stmt->execute([$sender]); $sender_balance = $stmt->fetchColumn(); if ($sender_balance < $amount) { die('Insufficient funds'); } $stmt = $db->prepare("UPDATE users SET balance = balance - ? WHERE username = ?"); $stmt->execute([$amount, $sender]); $stmt = $db->prepare("UPDATE users SET balance = balance + ? WHERE username = ?"); $stmt->execute([$amount, $recipient]); $stmt = $db->prepare(" INSERT INTO transactions (sender, recipient, amount) VALUES (?, ?, ?) "); $stmt->execute([$sender, $recipient, $amount]); $db->commit(); header('Location: dashboard.php'); exit; } catch (PDOException $e) { $db->rollBack(); die('Transfer failed: ' . $e->getMessage()); } } ?> ================================================================================ FILE 5: vulnerable/logout.php ================================================================================ ================================================================================ FILE 6: vulnerable/styles.css ================================================================================ body { font-family: Arial, sans-serif; background: #f0f2f5; padding: 20px; } .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; } h1 { color: #333; text-align: center; } .balance { background: #4CAF50; color: white; padding: 20px; text-align: center; font-size: 24px; } .warning { background: #ff5722; color: white; padding: 15px; text-align: center; font-weight: bold; } .success { background: #4CAF50; color: white; padding: 15px; text-align: center; font-weight: bold; } .error { background: #f44336; color: white; padding: 10px; } input, select { width: 100%; padding: 10px; border: 1px solid #ddd; } button { width: 100%; padding: 12px; background: #2196F3; color: white; border: none; cursor: pointer; } table { width: 100%; border-collapse: collapse; } ================================================================================ ATTACKER VERSION - File 7 ================================================================================ ================================================================================ FILE 7: attacker/malicious.html (CSRF EXPLOIT) ================================================================================ Free Prize!

Congratulations!

You've Been Selected!

You have won a $1,000 cash prize from our exclusive promotion!

[For Examiner]: Select target bank below, login to that bank in another tab, then click the prize button.
[WARNING] Attacking VULNERABLE bank - Attack should SUCCEED

Click the button below to claim your reward now:

*This is an educational demonstration for Exercise 4.2
Current Target: localhost:8000 (Vulnerable)

================================================================================ SECURE VERSION - Files 8-13 (WITH CSRF PROTECTION) ================================================================================ ================================================================================ FILE 8: secure/init_db.php ================================================================================ setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $db->exec(" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, balance REAL NOT NULL DEFAULT 0 ) "); $db->exec(" CREATE TABLE IF NOT EXISTS transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT NOT NULL, recipient TEXT NOT NULL, amount REAL NOT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP ) "); $db->exec("DELETE FROM users"); $db->exec("DELETE FROM transactions"); $users = [ ['alice', 'alice123', 5000], ['bob', 'bob123', 3000], ['eve', 'eve123', 1000] ]; $stmt = $db->prepare("INSERT INTO users (username, password, balance) VALUES (?, ?, ?)"); foreach ($users as $user) { $stmt->execute($user); } echo "✓ Secure database initialized successfully!\n"; echo "Test users created:\n"; echo " alice/alice123 - \$5,000\n"; echo " bob/bob123 - \$3,000\n"; echo " eve/eve123 - \$1,000\n"; } catch (PDOException $e) { die("✗ Database error: " . $e->getMessage()); } ?> ================================================================================ FILE 9: secure/index.php ================================================================================ 3600, 'path' => '/', 'domain' => 'localhost', 'secure' => false, 'httponly' => true, 'samesite' => 'Lax' ]); if (isset($_SESSION['user'])) { header('Location: dashboard.php'); exit; } $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $username = $_POST['username'] ?? ''; $password = $_POST['password'] ?? ''; try { $db = new PDO('sqlite:bank_secure.db'); $stmt = $db->prepare("SELECT * FROM users WHERE username = ? AND password = ?"); $stmt->execute([$username, $password]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if ($user) { $_SESSION['user'] = $username; $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); header('Location: dashboard.php'); exit; } else { $error = 'Invalid credentials'; } } catch (PDOException $e) { $error = 'Database error'; } } ?> Secure Bank - Login

Secure Bank Login

CSRF PROTECTION ENABLED

Test users: alice/alice123, bob/bob123, eve/eve123

================================================================================ FILE 10: secure/dashboard.php ================================================================================ prepare("SELECT balance FROM users WHERE username = ?"); $stmt->execute([$username]); $balance = $stmt->fetchColumn(); $stmt = $db->prepare(" SELECT * FROM transactions WHERE sender = ? OR recipient = ? ORDER BY timestamp DESC LIMIT 10 "); $stmt->execute([$username, $username]); $transactions = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { die('Database error'); } ?> Dashboard - Secure Bank

Welcome,

Current Balance: $
PROTECTED: CSRF tokens enabled!

Transfer Money

Recent Transactions

FromToAmountTime
$
Logout
================================================================================ FILE 11: secure/transfer.php ( PROTECTED!) ================================================================================ beginTransaction(); $stmt = $db->prepare("SELECT balance FROM users WHERE username = ?"); $stmt->execute([$sender]); $sender_balance = $stmt->fetchColumn(); if ($sender_balance < $amount) { die('Insufficient funds'); } $stmt = $db->prepare("UPDATE users SET balance = balance - ? WHERE username = ?"); $stmt->execute([$amount, $sender]); $stmt = $db->prepare("UPDATE users SET balance = balance + ? WHERE username = ?"); $stmt->execute([$amount, $recipient]); $stmt = $db->prepare("INSERT INTO transactions (sender, recipient, amount) VALUES (?, ?, ?)"); $stmt->execute([$sender, $recipient, $amount]); $db->commit(); $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); header('Location: dashboard.php'); exit; } catch (PDOException $e) { $db->rollBack(); die('Transfer failed: ' . $e->getMessage()); } } ?> ================================================================================ FILE 12: secure/logout.php ================================================================================ ================================================================================ FILE 13: secure/styles.css ================================================================================ body { font-family: Arial, sans-serif; background: #f0f2f5; padding: 20px; } .container { max-width: 600px; margin: 0 auto; background: white; padding: 30px; } h1 { color: #333; text-align: center; } .balance { background: #4CAF50; color: white; padding: 20px; text-align: center; font-size: 24px; } .warning { background: #ff5722; color: white; padding: 15px; text-align: center; font-weight: bold; } .success { background: #4CAF50; color: white; padding: 15px; text-align: center; font-weight: bold; } .error { background: #f44336; color: white; padding: 10px; } input, select { width: 100%; padding: 10px; border: 1px solid #ddd; } button { width: 100%; padding: 12px; background: #2196F3; color: white; border: none; cursor: pointer; } table { width: 100%; border-collapse: collapse; } ================================================================================ COUNTERMEASURES SUMMARY ================================================================================ IMPLEMENTED CSRF PROTECTIONS (in secure/ version): 1. Synchronizer Token Pattern (CSRF Tokens) - Generated on login: bin2hex(random_bytes(32)) - Embedded in forms as hidden field - Validated on transfer.php submission - Regenerated after each use 2. SameSite Cookie Attribute - session_set_cookie_params(['samesite' => 'Lax']) - Blocks cross-site cookie transmission - Modern browser defense 3. Referer Header Validation - Checks HTTP_REFERER header - Ensures request originates from same domain - Fallback defense (can be stripped by proxies) 4. HttpOnly Cookie Flag - Prevents JavaScript access to session cookie - Mitigates XSS-based session theft 5. Token Regeneration - New token generated after each transfer - Prevents token reuse attacks ================================================================================ END OF CODE ================================================================================ References: - PHP CSRF Tutorial: https://www.phptutorial.net/php-tutorial/php-csrf/ - OWASP CSRF Prevention: https://owasp.org/www-community/attacks/csrf - RFC 6265bis (SameSite): https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis