406 lines
15 KiB
PHP
406 lines
15 KiB
PHP
<?php
|
||
/**
|
||
* WP Multi – Modul: Brute-Force-Schutz
|
||
*
|
||
* Automatisch aus wp-multi.php ausgelagert. Wird über den Loader in
|
||
* wp-multi.php eingebunden (nur wenn das WP Multi Toolkit aktiv ist).
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) { exit; }
|
||
|
||
/*
|
||
* Schutz vor Brute-Force-Angriffen mit wöchentlicher Zusammenfassung
|
||
* Sperr-E-Mails entfernt, Zusammenfassung deaktivierbar unter Benutzer mit verbessertem Design
|
||
*/
|
||
|
||
// Funktion zur Erfassung der echten IP-Adresse des Benutzers
|
||
function get_user_ip() {
|
||
if (!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) {
|
||
return $_SERVER['HTTP_CLIENT_IP'];
|
||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
|
||
$ip = trim($ips[0]);
|
||
return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : $_SERVER['REMOTE_ADDR'];
|
||
}
|
||
return filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0';
|
||
}
|
||
|
||
// Funktion zur Verfolgung von fehlgeschlagenen Anmeldeversuchen
|
||
function wp_multi_log_failed_login($username) {
|
||
global $wpdb;
|
||
|
||
$ip = get_user_ip();
|
||
if ($ip === '0.0.0.0') {
|
||
return;
|
||
}
|
||
|
||
$blocked_table = $wpdb->prefix . 'blocked_ips';
|
||
$attempts_table = $wpdb->prefix . 'login_attempts';
|
||
$block_threshold = 5;
|
||
|
||
// Anmeldeversuch in attempts-Tabelle speichern
|
||
$wpdb->insert(
|
||
$attempts_table,
|
||
array(
|
||
'ip' => $ip,
|
||
'username' => $username,
|
||
'attempt_time' => current_time('mysql'),
|
||
),
|
||
array('%s', '%s', '%s')
|
||
);
|
||
|
||
// Prüfen, ob IP bereits in blocked_ips existiert
|
||
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM $blocked_table WHERE ip = %s", $ip));
|
||
|
||
if ($row) {
|
||
$wpdb->update(
|
||
$blocked_table,
|
||
array(
|
||
'attempts' => $row->attempts + 1,
|
||
'last_attempt' => current_time('mysql'),
|
||
),
|
||
array('ip' => $ip),
|
||
array('%d', '%s'),
|
||
array('%s')
|
||
);
|
||
$attempts = $row->attempts + 1;
|
||
} else {
|
||
$wpdb->insert(
|
||
$blocked_table,
|
||
array(
|
||
'ip' => $ip,
|
||
'attempts' => 1,
|
||
'last_attempt' => current_time('mysql'),
|
||
),
|
||
array('%s', '%d', '%s')
|
||
);
|
||
$attempts = 1;
|
||
}
|
||
|
||
// IP sperren, wenn Schwellenwert erreicht
|
||
if ($attempts >= $block_threshold) {
|
||
wp_die(
|
||
__('Deine IP-Adresse wurde aufgrund zu vieler Fehlversuche gesperrt. Bitte versuche es später noch einmal.', 'wp-multi'),
|
||
__('Zugriff gesperrt', 'wp-multi'),
|
||
array('response' => 403)
|
||
);
|
||
}
|
||
}
|
||
|
||
// Hook für fehlgeschlagene Anmeldungen
|
||
add_action('wp_login_failed', 'wp_multi_log_failed_login', 10, 1);
|
||
|
||
// Funktion zur Erstellung der Tabellen
|
||
function wp_multi_create_blocked_ips_table() {
|
||
global $wpdb;
|
||
|
||
$blocked_table = $wpdb->prefix . 'blocked_ips';
|
||
$attempts_table = $wpdb->prefix . 'login_attempts';
|
||
$charset_collate = $wpdb->get_charset_collate();
|
||
$version = get_option('wp_multi_blocked_ips_version', '1.0');
|
||
|
||
if (version_compare($version, '1.1', '<')) {
|
||
$sql_blocked = "CREATE TABLE $blocked_table (
|
||
id mediumint(9) NOT NULL AUTO_INCREMENT,
|
||
ip varchar(45) NOT NULL,
|
||
attempts int NOT NULL DEFAULT 0,
|
||
last_attempt datetime NOT NULL,
|
||
PRIMARY KEY (id),
|
||
KEY ip (ip)
|
||
) $charset_collate;";
|
||
|
||
$sql_attempts = "CREATE TABLE $attempts_table (
|
||
id mediumint(9) NOT NULL AUTO_INCREMENT,
|
||
ip varchar(45) NOT NULL,
|
||
username varchar(255) NOT NULL,
|
||
attempt_time datetime NOT NULL,
|
||
PRIMARY KEY (id),
|
||
KEY ip (ip),
|
||
KEY attempt_time (attempt_time)
|
||
) $charset_collate;";
|
||
|
||
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
||
dbDelta($sql_blocked);
|
||
dbDelta($sql_attempts);
|
||
update_option('wp_multi_blocked_ips_version', '1.1');
|
||
}
|
||
}
|
||
register_activation_hook(WP_MULTI_FILE, 'wp_multi_create_blocked_ips_table');
|
||
|
||
// Wöchentliche Zusammenfassung
|
||
function wp_multi_send_weekly_summary() {
|
||
global $wpdb;
|
||
|
||
// Prüfen, ob Zusammenfassung aktiviert ist
|
||
$summary_enabled = get_option('wp_multi_summary_enabled', 1);
|
||
if (!$summary_enabled) {
|
||
return;
|
||
}
|
||
|
||
$attempts_table = $wpdb->prefix . 'login_attempts';
|
||
$last_email_time = get_option('wp_multi_last_summary_email', 0);
|
||
$current_time = time();
|
||
|
||
// Prüfen, ob eine Woche vergangen ist (7 Tage = 604800 Sekunden)
|
||
if (($current_time - $last_email_time) < 604800) {
|
||
return;
|
||
}
|
||
|
||
// Zeitraum für die Zusammenfassung (letzte Woche)
|
||
$week_ago = date('Y-m-d H:i:s', strtotime('-7 days'));
|
||
$now = date('Y-m-d H:i:s');
|
||
|
||
// Gesamtzahl der Anmeldeversuche
|
||
$total_attempts = $wpdb->get_var(
|
||
$wpdb->prepare(
|
||
"SELECT COUNT(*) FROM $attempts_table WHERE attempt_time >= %s",
|
||
$week_ago
|
||
)
|
||
);
|
||
$total_attempts = $total_attempts ? $total_attempts : 0;
|
||
|
||
// Top 10 IPs mit den meisten Anmeldeversuchen
|
||
$top_attempts = $wpdb->get_results(
|
||
$wpdb->prepare(
|
||
"SELECT ip, username, COUNT(*) as attempt_count, MAX(attempt_time) as last_attempt
|
||
FROM $attempts_table
|
||
WHERE attempt_time >= %s
|
||
GROUP BY ip, username
|
||
ORDER BY attempt_count DESC
|
||
LIMIT 10",
|
||
$week_ago
|
||
)
|
||
);
|
||
|
||
// E-Mail-Inhalt
|
||
$message = __("Wöchentliche Anmeldeversuche-Zusammenfassung\n\n", 'wp-multi');
|
||
$message .= sprintf(__("Zeitraum: %s bis %s\n\n", 'wp-multi'), $week_ago, $now);
|
||
$message .= sprintf(__("Gesamtzahl der Anmeldeversuche: %d\n\n", 'wp-multi'), $total_attempts);
|
||
$message .= __("Top 10 Anmeldeversuche (nach IP und Benutzername):\n", 'wp-multi');
|
||
|
||
if ($top_attempts) {
|
||
foreach ($top_attempts as $index => $attempt) {
|
||
$message .= sprintf(
|
||
__("%d. IP: %s, Benutzername: %s, Versuche: %d, Letzter Versuch: %s\n", 'wp-multi'),
|
||
$index + 1,
|
||
$attempt->ip,
|
||
$attempt->username,
|
||
$attempt->attempt_count,
|
||
$attempt->last_attempt
|
||
);
|
||
}
|
||
} else {
|
||
$message .= __("Keine Anmeldeversuche in diesem Zeitraum.\n", 'wp-multi');
|
||
}
|
||
|
||
// E-Mail an Admin senden
|
||
$admin_email = get_option('admin_email');
|
||
wp_mail(
|
||
$admin_email,
|
||
__('Wöchentliche Anmeldeversuche-Zusammenfassung', 'wp-multi'),
|
||
$message,
|
||
array('Content-Type: text/plain; charset=UTF-8')
|
||
);
|
||
|
||
// Aktualisiere den Zeitstempel der letzten E-Mail
|
||
update_option('wp_multi_last_summary_email', $current_time);
|
||
}
|
||
|
||
// Planen der wöchentlichen Zusammenfassung (jeden Montag um 8:00 Uhr)
|
||
function wp_multi_schedule_weekly_summary() {
|
||
if (!wp_next_scheduled('wp_multi_weekly_summary_event')) {
|
||
wp_schedule_event(strtotime('next Monday 08:00'), 'weekly', 'wp_multi_weekly_summary_event');
|
||
}
|
||
}
|
||
add_action('wp', 'wp_multi_schedule_weekly_summary');
|
||
|
||
// Hook für die Ausführung der Zusammenfassung
|
||
add_action('wp_multi_weekly_summary_event', 'wp_multi_send_weekly_summary');
|
||
|
||
// Einstellungsoption für die Zusammenfassung
|
||
function wp_multi_users_register_settings() {
|
||
add_option('wp_multi_summary_enabled', 1);
|
||
register_setting('wp_multi_users_settings_group', 'wp_multi_summary_enabled', array(
|
||
'type' => 'integer',
|
||
'sanitize_callback' => 'absint',
|
||
'default' => 1,
|
||
));
|
||
|
||
// Settings Section hinzufügen
|
||
add_settings_section(
|
||
'wp_multi_security_section',
|
||
__('Brute-Force-Schutz Einstellungen', 'wp-multi'),
|
||
'wp_multi_security_section_callback',
|
||
'wp_multi_users_security_settings'
|
||
);
|
||
|
||
// Settings Field hinzufügen
|
||
add_settings_field(
|
||
'wp_multi_summary_enabled',
|
||
__('Wöchentliche Zusammenfassung', 'wp-multi'),
|
||
'wp_multi_summary_enabled_callback',
|
||
'wp_multi_users_security_settings',
|
||
'wp_multi_security_section'
|
||
);
|
||
}
|
||
add_action('admin_init', 'wp_multi_users_register_settings');
|
||
|
||
// Callback für die Settings Section
|
||
function wp_multi_security_section_callback() {
|
||
echo '<p>' . __('Konfiguriere die Sicherheitseinstellungen für den Brute-Force-Schutz deiner Website. Aktiviere oder deaktiviere die wöchentliche Zusammenfassung der fehlgeschlagenen Anmeldeversuche.', 'wp-multi') . '</p>';
|
||
}
|
||
|
||
// Callback für das Settings Field
|
||
function wp_multi_summary_enabled_callback() {
|
||
$summary_enabled = get_option('wp_multi_summary_enabled', 1);
|
||
?>
|
||
<input type="checkbox" name="wp_multi_summary_enabled" id="wp_multi_summary_enabled" value="1" <?php checked(1, $summary_enabled); ?> />
|
||
<label for="wp_multi_summary_enabled"><?php _e('Wöchentliche E-Mail-Zusammenfassung für fehlgeschlagene Anmeldeversuche aktivieren', 'wp-multi'); ?></label>
|
||
<p class="description"><?php _e('Wenn aktiviert, erhält der Administrator jeden Montag um 8:00 Uhr eine E-Mail mit einer Zusammenfassung der fehlgeschlagenen Anmeldeversuche der letzten Woche.', 'wp-multi'); ?></p>
|
||
<?php
|
||
}
|
||
|
||
// Blockierte IPs & Sicherheitseinstellungen werden zentral in wp_multi_register_admin_menus() registriert.
|
||
|
||
// Einstellungsseite unter Benutzer
|
||
function wp_multi_users_security_settings_page() {
|
||
wpmt_admin_page_open(
|
||
__('Benutzer-Sicherheit', 'wp-multi'),
|
||
__('Brute-Force-Schutz und Benachrichtigungen für fehlgeschlagene Logins', 'wp-multi')
|
||
);
|
||
|
||
wpmt_admin_card_open(__('Brute-Force-Schutz', 'wp-multi'));
|
||
?>
|
||
<p><?php _e('Verwalte die Einstellungen für den Schutz vor Brute-Force-Angriffen. Passe die Benachrichtigungen für fehlgeschlagene Anmeldeversuche an.', 'wp-multi'); ?></p>
|
||
<form method="post" action="options.php">
|
||
<?php
|
||
settings_fields('wp_multi_users_settings_group');
|
||
do_settings_sections('wp_multi_users_security_settings');
|
||
submit_button(__('Einstellungen speichern', 'wp-multi'));
|
||
?>
|
||
</form>
|
||
<?php
|
||
wpmt_admin_card_close();
|
||
|
||
wpmt_admin_page_close();
|
||
}
|
||
|
||
// Anzeige der blockierten IPs im Admin-Bereich
|
||
function wp_multi_display_blocked_ips() {
|
||
global $wpdb;
|
||
$table_name = $wpdb->prefix . 'blocked_ips';
|
||
|
||
$five_days_ago = date('Y-m-d H:i:s', strtotime('-5 days'));
|
||
$per_page = 50;
|
||
$page = max(1, isset($_GET['paged']) ? intval($_GET['paged']) : 1);
|
||
$offset = ($page - 1) * $per_page;
|
||
|
||
$blocked_ips = $wpdb->get_results(
|
||
$wpdb->prepare(
|
||
"SELECT * FROM $table_name WHERE last_attempt >= %s ORDER BY last_attempt DESC LIMIT %d OFFSET %d",
|
||
$five_days_ago,
|
||
$per_page,
|
||
$offset
|
||
)
|
||
);
|
||
|
||
$total_ips = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $table_name WHERE last_attempt >= %s", $five_days_ago));
|
||
$total_pages = ceil($total_ips / $per_page);
|
||
|
||
wpmt_admin_page_open(
|
||
__('Blockierte IPs', 'wp-multi'),
|
||
__('Vom Brute-Force-Schutz erfasste IP-Adressen der letzten 5 Tage', 'wp-multi')
|
||
);
|
||
|
||
wpmt_admin_card_open();
|
||
if (empty($blocked_ips)) {
|
||
wpmt_admin_notice('info', __('Keine blockierten IPs gefunden.', 'wp-multi'));
|
||
} else {
|
||
?>
|
||
<div class="wpm-table-wrap">
|
||
<table class="wpm-table">
|
||
<thead>
|
||
<tr>
|
||
<th><?php _e('ID', 'wp-multi'); ?></th>
|
||
<th><?php _e('IP-Adresse', 'wp-multi'); ?></th>
|
||
<th><?php _e('Versuche', 'wp-multi'); ?></th>
|
||
<th><?php _e('Letzter Versuch', 'wp-multi'); ?></th>
|
||
<th><?php _e('Aktionen', 'wp-multi'); ?></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($blocked_ips as $ip) : ?>
|
||
<tr>
|
||
<td><?php echo esc_html($ip->id); ?></td>
|
||
<td><?php echo esc_html($ip->ip); ?></td>
|
||
<td><span class="wpm-badge <?php echo $ip->attempts >= 5 ? 'wpm-badge--danger' : 'wpm-badge--warning'; ?>"><?php echo esc_html($ip->attempts); ?></span></td>
|
||
<td><?php echo esc_html($ip->last_attempt); ?></td>
|
||
<td>
|
||
<a class="wpm-btn wpm-btn--danger" href="<?php echo esc_url(wp_nonce_url(admin_url('admin-post.php?action=remove_blocked_ip&id=' . $ip->id), 'wp_multi_remove_blocked_ip_' . $ip->id)); ?>">
|
||
<?php _e('Entfernen', 'wp-multi'); ?>
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<?php if ($total_pages > 1) : ?>
|
||
<div class="tablenav">
|
||
<div class="tablenav-pages">
|
||
<?php
|
||
echo paginate_links(array(
|
||
'base' => add_query_arg('paged', '%#%'),
|
||
'format' => '',
|
||
'prev_text' => __('«'),
|
||
'next_text' => __('»'),
|
||
'total' => $total_pages,
|
||
'current' => $page,
|
||
));
|
||
?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php
|
||
}
|
||
wpmt_admin_card_close();
|
||
|
||
// Aufräumen: alte Einträge mit wenigen Versuchen entfernen
|
||
$three_days_ago = date('Y-m-d H:i:s', strtotime('-3 days'));
|
||
$wpdb->query(
|
||
$wpdb->prepare(
|
||
"DELETE FROM $table_name WHERE attempts < 10 AND last_attempt < %s",
|
||
$three_days_ago
|
||
)
|
||
);
|
||
|
||
wpmt_admin_page_close();
|
||
}
|
||
|
||
// Funktion zum Entfernen einer blockierten IP
|
||
function wp_multi_remove_blocked_ip() {
|
||
if (!current_user_can('manage_options')) {
|
||
wp_die(__('Du hast nicht die erforderlichen Berechtigungen.', 'wp-multi'), '', array('response' => 403));
|
||
}
|
||
|
||
$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||
|
||
if (!$id || !isset($_GET['_wpnonce']) || !wp_verify_nonce(wp_unslash($_GET['_wpnonce']), 'wp_multi_remove_blocked_ip_' . $id)) {
|
||
wp_die(__('Ungültige oder abgelaufene Anfrage.', 'wp-multi'), '', array('response' => 403));
|
||
}
|
||
|
||
global $wpdb;
|
||
|
||
if ($id > 0) {
|
||
$table_name = $wpdb->prefix . 'blocked_ips';
|
||
$wpdb->delete($table_name, array('id' => $id), array('%d'));
|
||
}
|
||
|
||
wp_safe_redirect(admin_url('admin.php?page=wp_multi_blocked_ips'));
|
||
exit;
|
||
}
|
||
add_action('admin_post_remove_blocked_ip', 'wp_multi_remove_blocked_ip');
|
||
|
||
|