diff --git a/public/composer.json b/composer.json similarity index 100% rename from public/composer.json rename to composer.json diff --git a/public/KONTAKTFORMULAR-STATUS.md b/docs/KONTAKTFORMULAR-STATUS.md similarity index 100% rename from public/KONTAKTFORMULAR-STATUS.md rename to docs/KONTAKTFORMULAR-STATUS.md diff --git a/public/README-EMAIL-SETUP.md b/docs/README-EMAIL-SETUP.md similarity index 100% rename from public/README-EMAIL-SETUP.md rename to docs/README-EMAIL-SETUP.md diff --git a/public/README-OPTIMIZATION.md b/docs/README-OPTIMIZATION.md similarity index 100% rename from public/README-OPTIMIZATION.md rename to docs/README-OPTIMIZATION.md diff --git a/public/README-STRUCTURE.md b/docs/README-STRUCTURE.md similarity index 100% rename from public/README-STRUCTURE.md rename to docs/README-STRUCTURE.md diff --git a/public/.htaccess b/public/.htaccess index a07a21c..9238bf3 100644 --- a/public/.htaccess +++ b/public/.htaccess @@ -8,6 +8,12 @@ Header always set X-XSS-Protection "1; mode=block" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()" + + # Content Security Policy - Schutz vor XSS und Code-Injection + Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' https://cdn.hexahost.de data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" + + # Strict-Transport-Security (HSTS) - Erzwingt HTTPS + Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" # HTTPS erzwingen (falls SSL verfügbar) @@ -48,6 +54,16 @@ Deny from all +# Config-Verzeichnis schützen + + RewriteRule ^config/ - [F,L] + + +# Includes-Verzeichnis schützen (direkter Zugriff verhindern) + + RewriteRule ^includes/ - [F,L] + + # Logs-Verzeichnis schützen RewriteRule ^logs/ - [F,L] @@ -95,14 +111,25 @@ # Fehlerbehandlung -ErrorDocument 404 /404.html -ErrorDocument 500 /500.html +ErrorDocument 400 /404.php +ErrorDocument 401 /404.php +ErrorDocument 403 /404.php +ErrorDocument 404 /404.php +ErrorDocument 500 /500.php +ErrorDocument 502 /500.php +ErrorDocument 503 /500.php # Verzeichnis-Listing deaktivieren Options -Indexes # Datei-Zugriff beschränken - + Order Allow,Deny Deny from all + + +# Spezifische Ausnahmen für benötigte XML-Dateien + + Order Allow,Deny + Allow from all \ No newline at end of file diff --git a/public/404.php b/public/404.php new file mode 100644 index 0000000..39dcdfe --- /dev/null +++ b/public/404.php @@ -0,0 +1,73 @@ + + +
+
+
+
+
404
+

Seite nicht gefunden

+

Die angeforderte Seite existiert leider nicht oder wurde verschoben.

+ +
+
+
+
+ + + + diff --git a/public/500.php b/public/500.php new file mode 100644 index 0000000..e5c6ea6 --- /dev/null +++ b/public/500.php @@ -0,0 +1,73 @@ + + +
+
+
+
+
500
+

Interner Serverfehler

+

Es ist ein unerwarteter Fehler aufgetreten. Wir arbeiten bereits an der Lösung.

+ +
+
+
+
+ + + + diff --git a/public/assets/js/contact.js b/public/assets/js/contact.js index 0825812..a27478b 100644 --- a/public/assets/js/contact.js +++ b/public/assets/js/contact.js @@ -51,9 +51,6 @@ // Get form data const formData = new FormData(form); - // Add honeypot field (hidden field for bot protection) - formData.append('website', ''); // Honeypot field - // Basic validation const data = {}; for (let [key, value] of formData.entries()) { diff --git a/public/config.php b/public/config/config.php similarity index 100% rename from public/config.php rename to public/config/config.php diff --git a/public/contact-handler.php b/public/contact-handler.php index f98749f..a828f9e 100644 --- a/public/contact-handler.php +++ b/public/contact-handler.php @@ -10,7 +10,7 @@ if (session_status() === PHP_SESSION_NONE) { } // Konfiguration laden -require_once 'config.php'; +require_once 'config/config.php'; // Konfiguration verwenden $config = getHexaHostConfig(); @@ -113,6 +113,32 @@ function sanitizeInput($input) { return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8'); } +// Sichere IP-Adressen-Erkennung (auch hinter Proxies/Cloudflare) +function getClientIP() { + $ip_keys = [ + 'HTTP_CF_CONNECTING_IP', // Cloudflare + 'HTTP_X_FORWARDED_FOR', // Proxy + 'HTTP_X_REAL_IP', // Nginx Proxy + 'REMOTE_ADDR' // Standard + ]; + + foreach ($ip_keys as $key) { + if (!empty($_SERVER[$key])) { + // Bei X-Forwarded-For kann eine Liste von IPs kommen + $ip = explode(',', $_SERVER[$key])[0]; + $ip = trim($ip); + + // Validiere IP-Format + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { + return $ip; + } + } + } + + // Fallback auf REMOTE_ADDR (auch private IPs für lokale Entwicklung) + return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; +} + // SMTP E-Mail-Versand mit PHPMailer function sendEmail($data) { global $config; @@ -268,7 +294,7 @@ function generateEmailHTML($data) {
IP-Adresse:
-
' . $_SERVER['REMOTE_ADDR'] . '
+
' . htmlspecialchars(getClientIP()) . '
@@ -311,7 +337,7 @@ function generateEmailText($data) { $text .= "----------\n"; $text .= $data['message'] . "\n\n"; - $text .= "IP-Adresse: " . $_SERVER['REMOTE_ADDR'] . "\n"; + $text .= "IP-Adresse: " . getClientIP() . "\n"; $text .= "Zeitstempel: " . date('d.m.Y H:i:s') . "\n\n"; $text .= "---\n"; @@ -334,7 +360,7 @@ try { } // Rate Limiting Check - $client_ip = $_SERVER['REMOTE_ADDR']; + $client_ip = getClientIP(); if (!checkRateLimit($client_ip)) { http_response_code(429); echo json_encode([ diff --git a/public/contact.php b/public/contact.php index 8a6527a..c3c3ed8 100644 --- a/public/contact.php +++ b/public/contact.php @@ -97,6 +97,10 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
+ +
@@ -143,7 +147,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
diff --git a/public/includes/functions.php b/public/includes/functions.php index b944d8d..912433d 100644 --- a/public/includes/functions.php +++ b/public/includes/functions.php @@ -3,9 +3,30 @@ * Helper functions for HexaHost.de */ -// Start session for CSRF token +// Sichere Session-Konfiguration if (session_status() === PHP_SESSION_NONE) { + // Session-Cookie-Sicherheit + ini_set('session.cookie_httponly', 1); + ini_set('session.cookie_secure', isset($_SERVER['HTTPS']) ? 1 : 0); + ini_set('session.cookie_samesite', 'Strict'); + ini_set('session.use_strict_mode', 1); + ini_set('session.use_only_cookies', 1); + session_start(); + + // Session-ID regenerieren bei Login/wichtigen Aktionen (Schutz vor Session Fixation) + if (!isset($_SESSION['initiated'])) { + session_regenerate_id(true); + $_SESSION['initiated'] = true; + } +} + +// PHP Error Display in Produktion deaktivieren +if (!defined('DEBUG_MODE') || !DEBUG_MODE) { + ini_set('display_errors', 0); + ini_set('display_startup_errors', 0); + error_reporting(E_ALL); + ini_set('log_errors', 1); } /** diff --git a/public/test-email.php b/scripts/test-email.php similarity index 100% rename from public/test-email.php rename to scripts/test-email.php