Enhance security and configuration of contact form: Added Content Security Policy and Strict-Transport-Security headers in .htaccess for improved security. Updated error handling to use a single 404.php for various error codes. Removed deprecated config.php and composer.json files, and implemented IP address detection for better security. Added honeypot field for bot protection in contact form and improved session security settings in functions.php.

This commit is contained in:
TheOnlyMace
2026-01-13 23:04:05 +01:00
parent a1b303edde
commit 2df47dc461
14 changed files with 233 additions and 12 deletions

View File

@@ -8,6 +8,12 @@
Header always set X-XSS-Protection "1; mode=block" Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()" 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"
</IfModule> </IfModule>
# HTTPS erzwingen (falls SSL verfügbar) # HTTPS erzwingen (falls SSL verfügbar)
@@ -48,6 +54,16 @@
Deny from all Deny from all
</Files> </Files>
# Config-Verzeichnis schützen
<IfModule mod_rewrite.c>
RewriteRule ^config/ - [F,L]
</IfModule>
# Includes-Verzeichnis schützen (direkter Zugriff verhindern)
<IfModule mod_rewrite.c>
RewriteRule ^includes/ - [F,L]
</IfModule>
# Logs-Verzeichnis schützen # Logs-Verzeichnis schützen
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteRule ^logs/ - [F,L] RewriteRule ^logs/ - [F,L]
@@ -95,14 +111,25 @@
</IfModule> </IfModule>
# Fehlerbehandlung # Fehlerbehandlung
ErrorDocument 404 /404.html ErrorDocument 400 /404.php
ErrorDocument 500 /500.html 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 # Verzeichnis-Listing deaktivieren
Options -Indexes Options -Indexes
# Datei-Zugriff beschränken # Datei-Zugriff beschränken
<FilesMatch "\.(htaccess|htpasswd|ini|log|sh|inc|bak)$"> <FilesMatch "\.(htaccess|htpasswd|ini|log|sh|inc|bak|sql|env|yml|yaml|json|xml|md)$">
Order Allow,Deny Order Allow,Deny
Deny from all Deny from all
</FilesMatch>
# Spezifische Ausnahmen für benötigte XML-Dateien
<FilesMatch "^(sitemap\.xml|robots\.txt)$">
Order Allow,Deny
Allow from all
</FilesMatch> </FilesMatch>

73
public/404.php Normal file
View File

@@ -0,0 +1,73 @@
<?php
require_once 'includes/functions.php';
// Page configuration
$page_title = '404 - Seite nicht gefunden | HexaHost.de';
$page_description = 'Die angeforderte Seite wurde nicht gefunden.';
$current_page = '404';
// Set 404 header
http_response_code(404);
// Include header
includeHeader($page_title, $page_description, $current_page);
?>
<main>
<section class="error-page">
<div class="container">
<div class="error-content glass-card">
<div class="error-code">404</div>
<h1>Seite nicht gefunden</h1>
<p>Die angeforderte Seite existiert leider nicht oder wurde verschoben.</p>
<div class="error-actions">
<a href="index.php" class="btn btn-primary">Zur Startseite</a>
<a href="contact.php" class="btn btn-secondary">Kontakt aufnehmen</a>
</div>
</div>
</div>
</section>
</main>
<style>
.error-page {
min-height: 60vh;
display: flex;
align-items: center;
justify-content: center;
padding: 4rem 0;
}
.error-content {
text-align: center;
padding: 3rem;
max-width: 500px;
}
.error-code {
font-size: 6rem;
font-weight: 700;
background: linear-gradient(135deg, #ff51f9, #a348ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 1rem;
}
.error-content h1 {
font-size: 1.75rem;
margin-bottom: 1rem;
}
.error-content p {
color: #888;
margin-bottom: 2rem;
}
.error-actions {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
</style>
<?php
includeFooter();
?>

73
public/500.php Normal file
View File

@@ -0,0 +1,73 @@
<?php
require_once 'includes/functions.php';
// Page configuration
$page_title = '500 - Serverfehler | HexaHost.de';
$page_description = 'Ein interner Serverfehler ist aufgetreten.';
$current_page = '500';
// Set 500 header
http_response_code(500);
// Include header
includeHeader($page_title, $page_description, $current_page);
?>
<main>
<section class="error-page">
<div class="container">
<div class="error-content glass-card">
<div class="error-code">500</div>
<h1>Interner Serverfehler</h1>
<p>Es ist ein unerwarteter Fehler aufgetreten. Wir arbeiten bereits an der Lösung.</p>
<div class="error-actions">
<a href="index.php" class="btn btn-primary">Zur Startseite</a>
<a href="contact.php" class="btn btn-secondary">Support kontaktieren</a>
</div>
</div>
</div>
</section>
</main>
<style>
.error-page {
min-height: 60vh;
display: flex;
align-items: center;
justify-content: center;
padding: 4rem 0;
}
.error-content {
text-align: center;
padding: 3rem;
max-width: 500px;
}
.error-code {
font-size: 6rem;
font-weight: 700;
background: linear-gradient(135deg, #ff51f9, #a348ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
margin-bottom: 1rem;
}
.error-content h1 {
font-size: 1.75rem;
margin-bottom: 1rem;
}
.error-content p {
color: #888;
margin-bottom: 2rem;
}
.error-actions {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
</style>
<?php
includeFooter();
?>

View File

@@ -51,9 +51,6 @@
// Get form data // Get form data
const formData = new FormData(form); const formData = new FormData(form);
// Add honeypot field (hidden field for bot protection)
formData.append('website', ''); // Honeypot field
// Basic validation // Basic validation
const data = {}; const data = {};
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {

View File

@@ -10,7 +10,7 @@ if (session_status() === PHP_SESSION_NONE) {
} }
// Konfiguration laden // Konfiguration laden
require_once 'config.php'; require_once 'config/config.php';
// Konfiguration verwenden // Konfiguration verwenden
$config = getHexaHostConfig(); $config = getHexaHostConfig();
@@ -113,6 +113,32 @@ function sanitizeInput($input) {
return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8'); 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 // SMTP E-Mail-Versand mit PHPMailer
function sendEmail($data) { function sendEmail($data) {
global $config; global $config;
@@ -268,7 +294,7 @@ function generateEmailHTML($data) {
<div class="field"> <div class="field">
<div class="label">IP-Adresse:</div> <div class="label">IP-Adresse:</div>
<div class="value">' . $_SERVER['REMOTE_ADDR'] . '</div> <div class="value">' . htmlspecialchars(getClientIP()) . '</div>
</div> </div>
<div class="field"> <div class="field">
@@ -311,7 +337,7 @@ function generateEmailText($data) {
$text .= "----------\n"; $text .= "----------\n";
$text .= $data['message'] . "\n\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 .= "Zeitstempel: " . date('d.m.Y H:i:s') . "\n\n";
$text .= "---\n"; $text .= "---\n";
@@ -334,7 +360,7 @@ try {
} }
// Rate Limiting Check // Rate Limiting Check
$client_ip = $_SERVER['REMOTE_ADDR']; $client_ip = getClientIP();
if (!checkRateLimit($client_ip)) { if (!checkRateLimit($client_ip)) {
http_response_code(429); http_response_code(429);
echo json_encode([ echo json_encode([

View File

@@ -97,6 +97,10 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
</div> </div>
<form class="contact-form glass-card" id="contactForm" action="contact-handler.php" method="POST"> <form class="contact-form glass-card" id="contactForm" action="contact-handler.php" method="POST">
<input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>"> <input type="hidden" name="csrf_token" value="<?php echo generateCSRFToken(); ?>">
<!-- Honeypot-Feld für Bot-Schutz (versteckt via CSS) -->
<div style="position: absolute; left: -9999px;" aria-hidden="true">
<input type="text" name="website" tabindex="-1" autocomplete="off">
</div>
<div class="form-row"> <div class="form-row">
<div class="form-group"> <div class="form-group">
<label for="firstName">Vorname *</label> <label for="firstName">Vorname *</label>
@@ -143,7 +147,7 @@ includeHeader($page_title, $page_description, $current_page, $additional_scripts
<div class="form-group checkbox-group"> <div class="form-group checkbox-group">
<label class="checkbox-label"> <label class="checkbox-label">
<input type="checkbox" id="privacy" name="privacy" required> <input type="checkbox" id="privacy" name="privacy" required>
Ich habe die <a href="#" target="_blank">Datenschutzerklärung</a> gelesen und stimme der Verarbeitung meiner Daten zu. * Ich habe die <a href="datenschutz.php" target="_blank">Datenschutzerklärung</a> gelesen und stimme der Verarbeitung meiner Daten zu. *
</label> </label>
</div> </div>
<div class="form-actions"> <div class="form-actions">

View File

@@ -3,9 +3,30 @@
* Helper functions for HexaHost.de * Helper functions for HexaHost.de
*/ */
// Start session for CSRF token // Sichere Session-Konfiguration
if (session_status() === PHP_SESSION_NONE) { 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_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);
} }
/** /**