Files
ukaiautomation/contact-handler.php
Peter 7e69cd0c19 Implement comprehensive spam protection for contact forms
- Add CSRF protection to quote form
- Add honeypot fields to both forms
- Expand spam keyword detection (25+ terms)
- Implement bot detection (user agent & timing validation)
- Add IP-based blocking system (24-hour blocks)
- Enhanced content filtering and validation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-17 18:43:06 +01:00

329 lines
11 KiB
PHP

<?php
// Enhanced Contact Form Handler with Security
session_start();
// Security headers
header('X-Content-Type-Options: nosniff');
header('X-Frame-Options: DENY');
header('X-XSS-Protection: 1; mode=block');
header('Content-Type: application/json');
// CSRF Protection
function generateCSRFToken() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
function validateCSRFToken($token) {
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
}
// Rate limiting (simple implementation)
function checkRateLimit() {
$ip = $_SERVER['REMOTE_ADDR'];
$key = 'contact_' . md5($ip);
if (!isset($_SESSION[$key])) {
$_SESSION[$key] = ['count' => 0, 'time' => time()];
}
$data = $_SESSION[$key];
// Reset counter if more than 1 hour has passed
if (time() - $data['time'] > 3600) {
$_SESSION[$key] = ['count' => 0, 'time' => time()];
$data = $_SESSION[$key];
}
// Allow max 5 submissions per hour
if ($data['count'] >= 5) {
return false;
}
return true;
}
// Input validation and sanitization
function validateInput($data, $type = 'text') {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
// Prevent header injection
$data = str_replace(array("\r", "\n", "%0a", "%0d"), '', $data);
switch ($type) {
case 'email':
$email = filter_var($data, FILTER_VALIDATE_EMAIL);
// Additional email validation to prevent header injection
if ($email && !preg_match('/[\r\n]/', $email)) {
return $email;
}
return false;
case 'phone':
return preg_match('/^[\+]?[0-9\s\-\(\)]+$/', $data) ? $data : false;
case 'text':
return strlen($data) > 0 ? $data : false;
case 'message':
return strlen($data) >= 10 ? $data : false;
default:
return $data;
}
}
// Response function
function sendResponse($success, $message, $data = null) {
$response = [
'success' => $success,
'message' => $message
];
if ($data !== null) {
$response['data'] = $data;
}
echo json_encode($response);
exit;
}
// Handle POST requests only
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
sendResponse(false, 'Invalid request method');
}
// Check referer to prevent external form submissions
$allowed_referers = ['ukdataservices.co.uk', 'www.ukdataservices.co.uk', 'localhost'];
$referer_valid = false;
if (isset($_SERVER['HTTP_REFERER'])) {
$referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
foreach ($allowed_referers as $allowed) {
if ($referer_host === $allowed || strpos($referer_host, $allowed) !== false) {
$referer_valid = true;
break;
}
}
}
// Allow direct access for testing but log it
if (!$referer_valid && !isset($_SERVER['HTTP_REFERER'])) {
error_log("Contact form accessed without referer from IP: " . $_SERVER['REMOTE_ADDR']);
}
// Check for blocked IPs
function checkBlockedIP() {
$ip = $_SERVER['REMOTE_ADDR'];
$blockFile = 'logs/blocked-ips.txt';
if (file_exists($blockFile)) {
$blockedIPs = file($blockFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($blockedIPs as $blockedEntry) {
$parts = explode('|', $blockedEntry);
if (isset($parts[0]) && $parts[0] === $ip) {
$blockTime = isset($parts[1]) ? (int)$parts[1] : 0;
// Block for 24 hours
if (time() - $blockTime < 86400) {
return false;
}
}
}
}
return true;
}
// Check for blocked IPs first
if (!checkBlockedIP()) {
sendResponse(false, 'Access temporarily restricted');
}
// Check rate limiting
if (!checkRateLimit()) {
sendResponse(false, 'Too many requests. Please try again later.');
}
// Validate and sanitize inputs
$name = validateInput($_POST['name'] ?? '', 'text');
$email = validateInput($_POST['email'] ?? '', 'email');
$company = validateInput($_POST['company'] ?? '', 'text');
$service = validateInput($_POST['service'] ?? '', 'text');
$message = validateInput($_POST['message'] ?? '', 'message');
// Validation
$errors = [];
if (!$name || strlen($name) < 2) {
$errors[] = 'Please enter a valid name (minimum 2 characters)';
}
if (!$email) {
$errors[] = 'Please enter a valid email address';
}
if (!$message) {
$errors[] = 'Please provide project details (minimum 10 characters)';
}
if (!empty($errors)) {
sendResponse(false, implode('. ', $errors));
}
// Spam protection - simple honeypot and content filtering
if (isset($_POST['website']) && !empty($_POST['website'])) {
// Honeypot field filled - likely spam
sendResponse(false, 'Spam detected');
}
// Enhanced spam protection - expanded keyword list
$spamKeywords = [
'viagra', 'cialis', 'casino', 'lottery', 'bitcoin', 'forex', 'loan', 'debt',
'pharmacy', 'click here', 'act now', 'limited time', 'risk free', 'guarantee',
'no obligation', 'free money', 'make money fast', 'work from home', 'get rich',
'investment opportunity', 'credit repair', 'refinance', 'consolidate debt',
'weight loss', 'miracle cure', 'lose weight', 'adult content', 'porn',
'sex', 'dating', 'singles', 'webcam', 'escort', 'massage'
];
$messageContent = strtolower($message . ' ' . $name . ' ' . $company);
foreach ($spamKeywords as $keyword) {
if (strpos($messageContent, $keyword) !== false) {
sendResponse(false, 'Invalid content detected');
}
}
// Bot detection - check for suspicious patterns
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$suspiciousAgents = ['curl', 'wget', 'python', 'bot', 'crawler', 'spider', 'scraper'];
foreach ($suspiciousAgents as $agent) {
if (stripos($userAgent, $agent) !== false) {
sendResponse(false, 'Automated submissions not allowed');
}
}
// Check submission speed (too fast = likely bot)
if (!isset($_SESSION['form_start_time'])) {
$_SESSION['form_start_time'] = time();
}
$submissionTime = time() - $_SESSION['form_start_time'];
if ($submissionTime < 5) { // Less than 5 seconds to fill form
sendResponse(false, 'Form submitted too quickly');
}
// Update rate limit counter
$ip = $_SERVER['REMOTE_ADDR'];
$key = 'contact_' . md5($ip);
$_SESSION[$key]['count']++;
// Prepare email content
$to = 'info@ukdataservices.co.uk';
$subject = 'New Contact Form Submission - UK Data Services';
// Create HTML email
$emailHTML = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>New Contact Form Submission</title>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; text-align: center; }
.content { background: #f9f9f9; padding: 20px; }
.field { margin-bottom: 15px; padding: 10px; background: white; border-left: 4px solid #667eea; }
.field-label { font-weight: bold; color: #667eea; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>New Contact Form Submission</h1>
<p>UK Data Services</p>
</div>
<div class="content">
<div class="field">
<div class="field-label">Name:</div>
<div>' . htmlspecialchars($name) . '</div>
</div>
<div class="field">
<div class="field-label">Email:</div>
<div>' . htmlspecialchars($email) . '</div>
</div>
<div class="field">
<div class="field-label">Company:</div>
<div>' . htmlspecialchars($company ?: 'Not provided') . '</div>
</div>
<div class="field">
<div class="field-label">Service Required:</div>
<div>' . htmlspecialchars($service ?: 'Not specified') . '</div>
</div>
<div class="field">
<div class="field-label">Project Details:</div>
<div>' . nl2br(htmlspecialchars($message)) . '</div>
</div>
<div class="field">
<div class="field-label">Submission Details:</div>
<div>
<strong>IP Address:</strong> ' . htmlspecialchars($_SERVER['REMOTE_ADDR']) . '<br>
<strong>User Agent:</strong> ' . htmlspecialchars($_SERVER['HTTP_USER_AGENT']) . '<br>
<strong>Timestamp:</strong> ' . date('Y-m-d H:i:s') . ' UTC<br>
<strong>Referrer:</strong> ' . htmlspecialchars($_SERVER['HTTP_REFERER'] ?? 'Direct') . '
</div>
</div>
</div>
<div class="footer">
<p>This email was sent from the UK Data Services contact form.</p>
</div>
</div>
</body>
</html>';
// Email headers
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$headers .= "From: \"UK Data Services Contact Form\" <noreply@ukdataservices.co.uk>\r\n";
$headers .= "Reply-To: " . $email . "\r\n";
$headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
$headers .= "X-Priority: 3\r\n";
// Create logs directory if it doesn't exist
if (!file_exists('logs')) {
mkdir('logs', 0755, true);
}
// Send email
try {
$emailSent = mail($to, $subject, $emailHTML, $headers);
if ($emailSent) {
// Log successful submission
$logEntry = date('Y-m-d H:i:s') . " - Contact form submission from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ")\n";
file_put_contents('logs/contact-submissions.log', $logEntry, FILE_APPEND | LOCK_EX);
sendResponse(true, 'Thank you for your message! We will get back to you within 24 hours.');
} else {
// Log failed email
$logEntry = date('Y-m-d H:i:s') . " - FAILED contact form submission from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ")\n";
file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX);
sendResponse(false, 'There was an error sending your message. Please try again or contact us directly.');
}
} catch (Exception $e) {
// Log exception
$logEntry = date('Y-m-d H:i:s') . " - EXCEPTION: " . $e->getMessage() . " from " . $email . " (" . $_SERVER['REMOTE_ADDR'] . ")\n";
file_put_contents('logs/contact-errors.log', $logEntry, FILE_APPEND | LOCK_EX);
sendResponse(false, 'There was an error processing your request. Please try again later.');
}
?>