261 lines
7.9 KiB
PHP
261 lines
7.9 KiB
PHP
<?php
|
|
// Fehlerausgabe komplett deaktivieren
|
|
error_reporting(0);
|
|
ini_set('display_errors', 0);
|
|
ini_set('log_errors', 1);
|
|
ini_set('error_log', '/path/to/error.log'); // Optional: Fehler in Log-Datei schreiben
|
|
|
|
// Buffer starten
|
|
ob_start();
|
|
|
|
// Sicherheitskonstante setzen
|
|
define('CONFIG_LOADED', true);
|
|
|
|
// Config laden (prüfe zuerst außerhalb des webroot)
|
|
if (file_exists(__DIR__ . '/../config.php')) {
|
|
require_once __DIR__ . '/../config.php';
|
|
} elseif (file_exists(__DIR__ . '/config.php')) {
|
|
require_once __DIR__ . '/config.php';
|
|
} else {
|
|
die('Configuration file not found');
|
|
}
|
|
|
|
require_once __DIR__ . '/../assets/vendor/php-email-form/php-email-form.php';
|
|
|
|
// Rate Limiting mit Konstanten aus Config
|
|
function checkRateLimit() {
|
|
$ip = $_SERVER['REMOTE_ADDR'];
|
|
$file = sys_get_temp_dir() . '/email_' . hash('sha256', $ip . date('Y-m-d-H'));
|
|
|
|
if (file_exists($file)) {
|
|
$data = json_decode(file_get_contents($file), true);
|
|
$now = time();
|
|
|
|
// Max RATE_LIMIT_MAX E-Mails pro RATE_LIMIT_WINDOW
|
|
if ($data['count'] >= RATE_LIMIT_MAX && ($now - $data['timestamp']) < RATE_LIMIT_WINDOW) {
|
|
return false;
|
|
}
|
|
|
|
if (($now - $data['timestamp']) >= RATE_LIMIT_WINDOW) {
|
|
$data = ['count' => 1, 'timestamp' => $now];
|
|
} else {
|
|
$data['count']++;
|
|
}
|
|
} else {
|
|
$data = ['count' => 1, 'timestamp' => time()];
|
|
}
|
|
|
|
file_put_contents($file, json_encode($data), LOCK_EX);
|
|
return true;
|
|
}
|
|
|
|
// Erweiterte Validierung mit XSS-Schutz
|
|
function validateInput($data) {
|
|
// Leere Felder prüfen
|
|
if (empty($data['name']) || empty($data['email']) || empty($data['message'])) {
|
|
return ['valid' => false, 'message' => 'Bitte füllen Sie alle Pflichtfelder aus.'];
|
|
}
|
|
|
|
// E-Mail-Format prüfen
|
|
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
|
|
return ['valid' => false, 'message' => 'Bitte geben Sie eine gültige E-Mail-Adresse ein.'];
|
|
}
|
|
|
|
// Zusätzliche E-Mail-Validierung (keine Header-Injection)
|
|
if (preg_match('/[\r\n]/', $data['email']) || preg_match('/[\r\n]/', $data['name'])) {
|
|
return ['valid' => false, 'message' => 'Ungültige Zeichen erkannt.'];
|
|
}
|
|
|
|
// Längenbeschränkungen
|
|
if (strlen($data['name']) > 100) {
|
|
return ['valid' => false, 'message' => 'Der Name ist zu lang.'];
|
|
}
|
|
|
|
if (strlen($data['message']) < 10) {
|
|
return ['valid' => false, 'message' => 'Ihre Nachricht ist zu kurz.'];
|
|
}
|
|
|
|
if (strlen($data['message']) > 5000) {
|
|
return ['valid' => false, 'message' => 'Ihre Nachricht ist zu lang.'];
|
|
}
|
|
|
|
// Spam-Wörter aus Config prüfen
|
|
foreach (SPAM_WORDS as $word) {
|
|
if (stripos($data['message'], $word) !== false || stripos($data['name'], $word) !== false) {
|
|
return ['valid' => false, 'message' => 'Ihre Nachricht wurde als Spam erkannt.'];
|
|
}
|
|
}
|
|
|
|
return ['valid' => true];
|
|
}
|
|
|
|
// XSS-Schutz für Ausgaben
|
|
function sanitizeOutput($string) {
|
|
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
// reCAPTCHA Validierung mit Config-Konstante
|
|
function validateRecaptcha($recaptchaResponse) {
|
|
if (empty($recaptchaResponse)) {
|
|
return false;
|
|
}
|
|
|
|
$secret = RECAPTCHA_SECRET;
|
|
$url = 'https://www.google.com/recaptcha/api/siteverify';
|
|
$data = [
|
|
'secret' => $secret,
|
|
'response' => $recaptchaResponse,
|
|
'remoteip' => $_SERVER['REMOTE_ADDR']
|
|
];
|
|
|
|
$options = [
|
|
'http' => [
|
|
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
|
|
'method' => 'POST',
|
|
'content' => http_build_query($data),
|
|
'timeout' => 10
|
|
],
|
|
'ssl' => [
|
|
'verify_peer' => true,
|
|
'verify_peer_name' => true,
|
|
]
|
|
];
|
|
|
|
$context = stream_context_create($options);
|
|
$result = @file_get_contents($url, false, $context);
|
|
|
|
if ($result === false) {
|
|
error_log('reCAPTCHA API request failed');
|
|
return false;
|
|
}
|
|
|
|
$responseData = json_decode($result);
|
|
return isset($responseData->success) && $responseData->success === true;
|
|
}
|
|
|
|
// Honeypot-Feld prüfen
|
|
if (!empty($_POST['website'])) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Spam erkannt.'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Zeitbasierte Validierung mit Config-Konstante
|
|
if (isset($_POST['form_start'])) {
|
|
$delta = time() - intval($_POST['form_start'] / 1000);
|
|
if ($delta < MIN_FORM_TIME) { // Zu schnell ausgefüllt
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Zu schnell abgesendet. Bitte versuchen Sie es erneut.'
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Hauptlogik
|
|
header('Content-Type: application/json');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
echo json_encode(['success' => false, 'message' => 'Nur POST-Requests erlaubt']);
|
|
exit;
|
|
}
|
|
|
|
try {
|
|
// Rate Limit prüfen
|
|
if (!checkRateLimit()) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Aus Sicherheitsgründen können Sie nur 5 Nachrichten pro Stunde senden. Bitte versuchen Sie es später erneut.'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// reCAPTCHA prüfen
|
|
$recaptchaResponse = $_POST['g-recaptcha-response'] ?? '';
|
|
if (!validateRecaptcha($recaptchaResponse)) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Bitte bestätigen Sie, dass Sie kein Robot sind.'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// Formulardaten sammeln und bereinigen
|
|
$formData = [
|
|
'name' => trim($_POST['name'] ?? ''),
|
|
'email' => trim($_POST['email'] ?? ''),
|
|
'mobile' => trim($_POST['mobilenumber'] ?? ''),
|
|
'message' => trim($_POST['message'] ?? '')
|
|
];
|
|
|
|
|
|
// E-Mail-Domain-Blacklist aus Config
|
|
foreach (SPAM_DOMAINS as $domain) {
|
|
if (stripos($formData['email'], $domain) !== false) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Bitte verwenden Sie eine echte E-Mail-Adresse.'
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Eingaben validieren
|
|
$validation = validateInput($formData);
|
|
if (!$validation['valid']) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => $validation['message']
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// E-Mail erstellen
|
|
$contact = new PHP_Email_Form;
|
|
$contact->ajax = true;
|
|
$contact->to = RECEIVING_EMAIL;
|
|
$contact->from_name = $formData['name'];
|
|
$contact->from_email = 'hkw@webfarben.net';
|
|
$contact->reply_to = $formData['email'];
|
|
$contact->subject = "Neue Kontaktanfrage von " . $formData['name'];
|
|
$contact->smtp = SMTP_CONFIG;
|
|
|
|
// Nachricht zusammenbauen
|
|
$contact->add_message($formData['name'], 'Name');
|
|
$contact->add_message($formData['email'], 'E-Mail');
|
|
$contact->add_message($formData['mobile'], 'Telefon');
|
|
$contact->add_message($formData['message'], 'Nachricht');
|
|
|
|
// Dateianhang verarbeiten mit Sicherheitschecks
|
|
if (isset($_FILES['resume']) && $_FILES['resume']['error'] == UPLOAD_ERR_OK) {
|
|
// Dateigröße prüfen
|
|
if ($_FILES['resume']['size'] > MAX_FILE_SIZE) {
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => 'Die Datei ist zu groß (max. 20 MB).'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
$contact->add_attachment('resume', 20, ALLOWED_FILE_TYPES);
|
|
}
|
|
|
|
// E-Mail senden
|
|
$result = $contact->send();
|
|
|
|
echo json_encode([
|
|
'success' => ($result === 'OK'),
|
|
'message' => ($result === 'OK')
|
|
? "Ihre Nachricht wurde erfolgreich gesendet an: " . RECEIVING_EMAIL
|
|
: "Fehler beim Senden: " . $result
|
|
]);
|
|
|
|
} catch (Exception $e) {
|
|
error_log("Mailer Error: " . $e->getMessage());
|
|
echo json_encode([
|
|
'success' => false,
|
|
'message' => "Ein Fehler ist aufgetreten: " . $e->getMessage()
|
|
]);
|
|
}
|