文章目录[隐藏]
实操指南:构建安全用户认证接口的5个重要原则
引言:为什么用户认证安全如此重要?
在当今数字化时代,用户认证系统是任何Web应用的第一道安全防线。据统计,超过80%的数据泄露事件与弱认证机制有关。对于基于WordPress的网站和应用来说,用户认证不仅是保护管理员后台的关键,更是保障用户数据安全的核心。
WordPress作为全球使用最广泛的CMS系统,其默认认证机制虽然基础可靠,但在面对日益复杂的网络攻击时,往往需要开发者进行强化和定制。本指南将基于WordPress代码开发,为行业新人和程序员提供构建安全用户认证接口的五个重要原则,帮助您打造坚不可摧的用户认证系统。
原则一:实施强密码策略与安全存储
1.1 WordPress密码机制解析
WordPress默认使用PHP的password_hash()函数进行密码哈希处理,采用bcrypt算法。这是当前行业标准,但我们可以进一步强化:
// WordPress核心密码验证函数示例
function wp_check_password($password, $hash, $user_id = '') {
global $wp_hasher;
if (empty($hash)) {
return false;
}
// 检查是否为旧版MD5哈希
if (strlen($hash) <= 32) {
$check = hash_equals($hash, md5($password));
if ($check && $user_id) {
// 重新哈希为更安全的格式
wp_set_password($password, $user_id);
}
return $check;
}
// 使用现代哈希验证
if (empty($wp_hasher)) {
require_once ABSPATH . WPINC . '/class-phpass.php';
$wp_hasher = new PasswordHash(8, true);
}
return $wp_hasher->CheckPassword($password, $hash);
}
1.2 强化密码策略实施
在WordPress中实施强密码策略:
// 在主题的functions.php或自定义插件中添加
add_filter('wp_authenticate_user', 'enforce_strong_password_policy', 10, 2);
function enforce_strong_password_policy($user, $password) {
// 密码最小长度检查
if (strlen($password) < 12) {
return new WP_Error('weak_password',
__('密码必须至少包含12个字符。', 'textdomain'));
}
// 密码复杂性检查
if (!preg_match('/[A-Z]/', $password) ||
!preg_match('/[a-z]/', $password) ||
!preg_match('/[0-9]/', $password) ||
!preg_match('/[^A-Za-z0-9]/', $password)) {
return new WP_Error('weak_password',
__('密码必须包含大写字母、小写字母、数字和特殊字符。', 'textdomain'));
}
// 检查常见弱密码
$weak_passwords = ['password', '123456', 'qwerty', 'admin123'];
if (in_array(strtolower($password), $weak_passwords)) {
return new WP_Error('weak_password',
__('您使用的密码太常见,请选择更复杂的密码。', 'textdomain'));
}
return $user;
}
1.3 密码哈希升级策略
确保始终使用最新的哈希算法:
// 定期检查并升级密码哈希
add_action('wp_login', 'check_password_hash_strength', 10, 2);
function check_password_hash_strength($user_login, $user) {
// 检查当前哈希算法是否需要升级
if (password_needs_rehash($user->user_pass, PASSWORD_ARGON2ID)) {
// 这里不直接更新,而是标记需要更新
update_user_meta($user->ID, 'needs_password_rehash', true);
}
}
原则二:实现多因素认证(MFA)
2.1 WordPress多因素认证基础
多因素认证是当前企业级安全标准。以下是在WordPress中实现TOTP(基于时间的一次性密码)的示例:
// 为用户启用TOTP功能
add_action('show_user_profile', 'add_2fa_settings_field');
add_action('edit_user_profile', 'add_2fa_settings_field');
function add_2fa_settings_field($user) {
if (!current_user_can('manage_options')) {
return;
}
$is_2fa_enabled = get_user_meta($user->ID, '2fa_enabled', true);
$2fa_secret = get_user_meta($user->ID, '2fa_secret', true);
if (empty($2fa_secret)) {
$2fa_secret = generate_2fa_secret();
update_user_meta($user->ID, '2fa_secret', $2fa_secret);
}
?>
<h3><?php _e('双因素认证', 'textdomain'); ?></h3>
<table class="form-table">
<tr>
<th><?php _e('启用双因素认证', 'textdomain'); ?></th>
<td>
<label for="2fa_enabled">
<input type="checkbox" name="2fa_enabled" id="2fa_enabled"
value="1" <?php checked($is_2fa_enabled, 1); ?> />
<?php _e('启用Google Authenticator双因素认证', 'textdomain'); ?>
</label>
<?php if ($is_2fa_enabled && $2fa_secret): ?>
<p class="description">
<?php _e('扫描二维码或输入密钥设置验证器:', 'textdomain'); ?><br>
<strong><?php echo chunk_split($2fa_secret, 4, ' '); ?></strong>
</p>
<?php endif; ?>
</td>
</tr>
</table>
<?php
}
2.2 TOTP验证实现
// 验证TOTP代码
function verify_2fa_code($user_id, $code) {
$secret = get_user_meta($user_id, '2fa_secret', true);
if (empty($secret)) {
return false;
}
require_once ABSPATH . 'wp-content/plugins/your-plugin/lib/phpotp/Token.php';
$token = new Token($secret);
$timestamp = time();
// 允许前后30秒的时间窗口
return $token->verify($code, $timestamp, 1);
}
// 在登录过程中集成2FA验证
add_filter('authenticate', 'integrate_2fa_authentication', 30, 3);
function integrate_2fa_authentication($user, $username, $password) {
if (is_wp_error($user) || !$user) {
return $user;
}
$is_2fa_enabled = get_user_meta($user->ID, '2fa_enabled', true);
if (!$is_2fa_enabled) {
return $user;
}
// 检查是否已提供2FA代码
if (empty($_POST['2fa_code'])) {
// 重定向到2FA验证页面
wp_redirect(add_query_arg('2fa_required', $user->ID, wp_login_url()));
exit;
}
if (!verify_2fa_code($user->ID, $_POST['2fa_code'])) {
return new WP_Error('invalid_2fa',
__('双因素认证代码无效。', 'textdomain'));
}
return $user;
}
2.3 备用验证码和恢复选项
// 生成备用验证码
function generate_backup_codes($user_id) {
$codes = [];
for ($i = 0; $i < 10; $i++) {
$codes[] = bin2hex(random_bytes(4)); // 8位十六进制代码
}
// 哈希存储备用码
$hashed_codes = array_map('wp_hash_password', $codes);
update_user_meta($user_id, '2fa_backup_codes', $hashed_codes);
// 返回明文代码供用户保存(仅显示一次)
return $codes;
}
// 验证备用码
function verify_backup_code($user_id, $code) {
$hashed_codes = get_user_meta($user_id, '2fa_backup_codes', true);
if (empty($hashed_codes)) {
return false;
}
foreach ($hashed_codes as $index => $hashed_code) {
if (wp_check_password($code, $hashed_code)) {
// 使用后移除该备用码
unset($hashed_codes[$index]);
update_user_meta($user_id, '2fa_backup_codes', array_values($hashed_codes));
return true;
}
}
return false;
}
原则三:防范暴力破解与自动化攻击
3.1 登录尝试限制
// 记录登录尝试
add_action('wp_login_failed', 'track_failed_login_attempt');
function track_failed_login_attempt($username) {
$ip_address = $_SERVER['REMOTE_ADDR'];
$transient_key = 'failed_login_' . md5($ip_address . $username);
$attempts = get_transient($transient_key);
$attempts = $attempts ? $attempts + 1 : 1;
// 存储15分钟
set_transient($transient_key, $attempts, 15 * MINUTE_IN_SECONDS);
// 如果尝试次数过多,锁定账户
if ($attempts >= 5) {
$lockout_key = 'login_lockout_' . md5($ip_address);
set_transient($lockout_key, true, 30 * MINUTE_IN_SECONDS);
// 记录安全日志
log_security_event('brute_force_attempt', [
'ip' => $ip_address,
'username' => $username,
'attempts' => $attempts,
'timestamp' => current_time('mysql')
]);
}
}
// 检查登录锁定
add_filter('authenticate', 'check_login_lockout', 5, 3);
function check_login_lockout($user, $username, $password) {
$ip_address = $_SERVER['REMOTE_ADDR'];
$lockout_key = 'login_lockout_' . md5($ip_address);
if (get_transient($lockout_key)) {
return new WP_Error('login_lockout',
__('由于多次登录失败,该IP已被暂时锁定。请30分钟后再试。', 'textdomain'));
}
return $user;
}
3.2 验证码集成
// 在登录表单添加验证码
add_action('login_form', 'add_login_captcha');
function add_login_captcha() {
// 简单的数学验证码
$num1 = rand(1, 10);
$num2 = rand(1, 10);
$_SESSION['captcha_answer'] = $num1 + $num2;
echo '<p>
<label for="captcha">' . sprintf(__('请计算: %d + %d = ?', 'textdomain'), $num1, $num2) . '<br>
<input type="text" name="captcha" id="captcha" class="input" value="" size="20"></label>
</p>';
}
// 验证验证码
add_filter('authenticate', 'verify_login_captcha', 20, 3);
function verify_login_captcha($user, $username, $password) {
if (empty($_POST['captcha']) || $_POST['captcha'] != $_SESSION['captcha_answer']) {
return new WP_Error('invalid_captcha',
__('验证码错误。', 'textdomain'));
}
return $user;
}
3.3 基于行为的异常检测
// 检测异常登录行为
add_action('wp_login', 'detect_anomalous_login', 10, 2);
function detect_anomalous_login($user_login, $user) {
$current_ip = $_SERVER['REMOTE_ADDR'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$known_ips = get_user_meta($user->ID, 'known_login_ips', true);
$known_devices = get_user_meta($user->ID, 'known_devices', true);
if (empty($known_ips)) {
$known_ips = [];
}
if (empty($known_devices)) {
$known_devices = [];
}
$device_fingerprint = md5($user_agent . $_SERVER['HTTP_ACCEPT_LANGUAGE']);
// 检查是否为新的IP地址或设备
if (!in_array($current_ip, $known_ips) || !in_array($device_fingerprint, $known_devices)) {
// 发送通知邮件
$admin_email = get_option('admin_email');
$subject = sprintf(__('异常登录检测 - %s', 'textdomain'), get_bloginfo('name'));
$message = sprintf(__(
'检测到用户 %s 的异常登录:nn' .
'时间:%sn' .
'IP地址:%sn' .
'用户代理:%sn' .
'如果是您本人的操作,请忽略此邮件。', 'textdomain'),
$user_login,
current_time('mysql'),
$current_ip,
$user_agent
);
wp_mail($admin_email, $subject, $message);
// 记录新的IP和设备
if (!in_array($current_ip, $known_ips)) {
$known_ips[] = $current_ip;
update_user_meta($user->ID, 'known_login_ips', $known_ips);
}
if (!in_array($device_fingerprint, $known_devices)) {
$known_devices[] = $device_fingerprint;
update_user_meta($user->ID, 'known_devices', $known_devices);
}
}
}
原则四:安全的会话管理
4.1 WordPress会话强化
// 增强WordPress会话安全性
add_action('init', 'enhance_session_security', 1);
function enhance_session_security() {
if (session_status() === PHP_SESSION_NONE) {
// 使用安全的会话配置
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', is_ssl() ? 1 : 0);
ini_set('session.cookie_samesite', 'Strict');
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_lifetime', 0); // 浏览器关闭时过期
session_start();
}
}
// 自定义会话管理
class Secure_Session_Handler {
private $table_name;
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'secure_sessions';
// 创建会话存储表
$this->create_table();
// 设置自定义会话处理器
session_set_save_handler(
[$this, 'open'],
[$this, 'close'],
[$this, 'read'],
[$this, 'write'],
[$this, 'destroy'],
[$this, 'gc']
);
}
private function create_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} (
session_id varchar(255) NOT NULL,
session_data longtext NOT NULL,
user_id bigint(20) unsigned DEFAULT NULL,
ip_address varchar(45) DEFAULT NULL,
user_agent text,
last_activity datetime NOT NULL,
PRIMARY KEY (session_id),
KEY user_id (user_id),
KEY last_activity (last_activity)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
public function read($session_id) {
global $wpdb;
$session = $wpdb->get_var($wpdb->prepare(
"SELECT session_data FROM {$this->table_name} WHERE session_id = %s",
$session_id
));
return $session ?: '';
}
public function write($session_id, $session_data) {
global $wpdb, $current_user;
$data = [
'session_id' => $session_id,
'session_data' => $session_data,
'user_id' => $current_user->ID ?: null,
'ip_address' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'last_activity' => current_time('mysql')
];
$wpdb->replace($this->table_name, $data);
return true;
}
}
// 初始化安全会话处理器
new Secure_Session_Handler();
4.2 会话固定攻击防护
// 防止会话固定攻击
add_action('wp_login', 'regenerate_session_on_login', 10, 2);
function regenerate_session_on_login($user_login, $user) {
// 登录时重新生成会话ID
session_regenerate_id(true);
// 将用户ID与会话关联
$_SESSION['user_id'] = $user->ID;
$_SESSION['login_time'] = time();
$_SESSION['login_ip'] = $_SERVER['REMOTE_ADDR'];
}
// 验证会话一致性
add_action('init', 'validate_session_integrity');
function validate_session_integrity() {
if (is_user_logged_in()) {
$current_user = wp_get_current_user();
// 检查会话中的用户ID是否与当前用户匹配
if (isset($_SESSION['user_id']) && $_SESSION['user_id'] != $current_user->ID) {
wp_logout();
wp_redirect(wp_login_url());
exit;
}
4.3 会话超时与并发控制
// 实现会话超时管理
add_action('init', 'manage_session_timeout');
function manage_session_timeout() {
if (!is_user_logged_in()) {
return;
}
$inactivity_timeout = 30 * MINUTE_IN_SECONDS; // 30分钟无操作超时
$absolute_timeout = 12 * HOUR_IN_SECONDS; // 12小时绝对超时
// 检查会话最后活动时间
if (isset($_SESSION['last_activity']) &&
(time() - $_SESSION['last_activity']) > $inactivity_timeout) {
// 会话超时,强制登出
wp_logout();
wp_redirect(add_query_arg('session_expired', '1', wp_login_url()));
exit;
}
// 检查绝对超时
if (isset($_SESSION['login_time']) &&
(time() - $_SESSION['login_time']) > $absolute_timeout) {
wp_logout();
wp_redirect(add_query_arg('session_expired', '1', wp_login_url()));
exit;
}
// 更新最后活动时间
$_SESSION['last_activity'] = time();
}
// 并发会话控制
add_action('wp_login', 'enforce_concurrent_session_limit', 10, 2);
function enforce_concurrent_session_limit($user_login, $user) {
$max_concurrent_sessions = 3; // 最大并发会话数
global $wpdb;
$table_name = $wpdb->prefix . 'secure_sessions';
// 获取用户当前活跃会话
$active_sessions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name}
WHERE user_id = %d AND last_activity > %s",
$user->ID,
date('Y-m-d H:i:s', time() - (30 * MINUTE_IN_SECONDS))
));
// 如果超过限制,终止最早的会话
if ($active_sessions >= $max_concurrent_sessions) {
$oldest_session = $wpdb->get_var($wpdb->prepare(
"SELECT session_id FROM {$table_name}
WHERE user_id = %d
ORDER BY last_activity ASC LIMIT 1",
$user->ID
));
if ($oldest_session) {
$wpdb->delete($table_name, ['session_id' => $oldest_session]);
}
}
}
// 登出时清理会话
add_action('wp_logout', 'cleanup_user_sessions');
function cleanup_user_sessions() {
if (isset($_SESSION['user_id'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'secure_sessions';
$wpdb->delete($table_name, [
'user_id' => $_SESSION['user_id'],
'session_id' => session_id()
]);
}
// 销毁当前会话
session_destroy();
}
原则五:全面的安全监控与日志记录
5.1 安全事件日志系统
// 创建安全日志表
function create_security_log_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'security_logs';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
event_type varchar(100) NOT NULL,
user_id bigint(20) unsigned DEFAULT NULL,
username varchar(255) DEFAULT NULL,
ip_address varchar(45) DEFAULT NULL,
user_agent text,
details longtext,
severity enum('low','medium','high','critical') DEFAULT 'low',
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY event_type (event_type),
KEY user_id (user_id),
KEY ip_address (ip_address),
KEY created_at (created_at),
KEY severity (severity)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta($sql);
}
register_activation_hook(__FILE__, 'create_security_log_table');
// 安全日志记录函数
function log_security_event($event_type, $data = []) {
global $wpdb, $current_user;
$table_name = $wpdb->prefix . 'security_logs';
$log_data = [
'event_type' => $event_type,
'user_id' => $current_user->ID ?? null,
'username' => $current_user->user_login ?? null,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'details' => json_encode($data, JSON_UNESCAPED_UNICODE),
'severity' => determine_event_severity($event_type),
'created_at' => current_time('mysql')
];
$wpdb->insert($table_name, $log_data);
// 高严重性事件实时通知
if (in_array($log_data['severity'], ['high', 'critical'])) {
send_security_alert($event_type, $data);
}
}
// 确定事件严重性
function determine_event_severity($event_type) {
$severity_map = [
'login_success' => 'low',
'login_failed' => 'medium',
'brute_force_attempt' => 'high',
'password_changed' => 'medium',
'role_changed' => 'high',
'suspicious_activity' => 'critical',
'file_tamper_detected' => 'critical'
];
return $severity_map[$event_type] ?? 'low';
}
// 关键安全事件钩子
add_action('wp_login', 'log_successful_login', 10, 2);
add_action('wp_login_failed', 'log_failed_login');
add_action('password_reset', 'log_password_reset', 10, 2);
add_action('set_user_role', 'log_role_change', 10, 3);
function log_successful_login($user_login, $user) {
log_security_event('login_success', [
'username' => $user_login,
'user_id' => $user->ID,
'login_time' => current_time('mysql')
]);
}
function log_failed_login($username) {
log_security_event('login_failed', [
'attempted_username' => $username,
'ip_address' => $_SERVER['REMOTE_ADDR']
]);
}
function log_password_reset($user, $new_pass) {
log_security_event('password_changed', [
'user_id' => $user->ID,
'username' => $user->user_login,
'changed_by' => get_current_user_id()
]);
}
function log_role_change($user_id, $role, $old_roles) {
log_security_event('role_changed', [
'user_id' => $user_id,
'new_role' => $role,
'old_roles' => $old_roles,
'changed_by' => get_current_user_id()
]);
}
5.2 实时安全监控与告警
// 实时安全监控类
class Security_Monitor {
private $alert_thresholds = [
'failed_logins' => 5, // 5次失败登录
'suspicious_ips' => 3, // 3个不同账户
'rapid_requests' => 100 // 100次/分钟
];
private $request_counts = [];
public function __construct() {
add_action('init', [$this, 'monitor_request_rate']);
add_action('wp_login_failed', [$this, 'analyze_login_patterns']);
add_action('shutdown', [$this, 'cleanup_monitoring_data']);
}
// 监控请求频率
public function monitor_request_rate() {
$ip = $_SERVER['REMOTE_ADDR'];
$current_minute = floor(time() / 60);
if (!isset($this->request_counts[$ip])) {
$this->request_counts[$ip] = [];
}
if (!isset($this->request_counts[$ip][$current_minute])) {
$this->request_counts[$ip][$current_minute] = 0;
}
$this->request_counts[$ip][$current_minute]++;
// 检查是否超过阈值
if ($this->request_counts[$ip][$current_minute] > $this->alert_thresholds['rapid_requests']) {
$this->trigger_rate_limit($ip);
}
}
// 分析登录模式
public function analyze_login_patterns($username) {
global $wpdb;
$ip = $_SERVER['REMOTE_ADDR'];
$table_name = $wpdb->prefix . 'security_logs';
// 检查同一IP尝试的不同用户名数量
$unique_usernames = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(DISTINCT username) FROM {$table_name}
WHERE ip_address = %s
AND event_type = 'login_failed'
AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)",
$ip
));
if ($unique_usernames >= $this->alert_thresholds['suspicious_ips']) {
log_security_event('suspicious_activity', [
'type' => 'multiple_account_attempts',
'ip' => $ip,
'unique_usernames' => $unique_usernames
]);
// 自动阻止该IP
$this->block_ip_temporarily($ip);
}
}
// 触发速率限制
private function trigger_rate_limit($ip) {
$block_key = 'rate_limit_block_' . md5($ip);
set_transient($block_key, true, 15 * MINUTE_IN_SECONDS);
log_security_event('rate_limit_exceeded', [
'ip' => $ip,
'requests_per_minute' => $this->request_counts[$ip][floor(time() / 60)]
]);
// 返回429 Too Many Requests
if (!headers_sent()) {
header('HTTP/1.1 429 Too Many Requests');
header('Retry-After: 900'); // 15分钟
exit('请求过于频繁,请稍后再试。');
}
}
// 临时阻止IP
private function block_ip_temporarily($ip) {
$block_key = 'ip_block_' . md5($ip);
set_transient($block_key, true, 60 * MINUTE_IN_SECONDS);
// 更新.htaccess或防火墙规则
$this->update_firewall_rules($ip);
}
// 清理监控数据
public function cleanup_monitoring_data() {
$current_minute = floor(time() / 60);
$retention_minutes = 5; // 保留5分钟数据
foreach ($this->request_counts as $ip => $minutes) {
foreach ($minutes as $minute => $count) {
if ($minute < $current_minute - $retention_minutes) {
unset($this->request_counts[$ip][$minute]);
}
}
if (empty($this->request_counts[$ip])) {
unset($this->request_counts[$ip]);
}
}
}
// 更新防火墙规则
private function update_firewall_rules($ip) {
$htaccess_path = ABSPATH . '.htaccess';
if (file_exists($htaccess_path) && is_writable($htaccess_path)) {
$rule = "n# 安全监控自动阻止nDeny from {$ip}n";
$content = file_get_contents($htaccess_path);
if (strpos($content, $rule) === false) {
file_put_contents($htaccess_path, $rule, FILE_APPEND);
}
}
}
}
// 初始化安全监控
new Security_Monitor();
5.3 安全报告与审计
// 安全报告生成类
class Security_Reporter {
// 生成每日安全报告
public function generate_daily_report() {
global $wpdb;
$table_name = $wpdb->prefix . 'security_logs';
$yesterday = date('Y-m-d', strtotime('-1 day'));
$report_data = [
'date' => $yesterday,
'total_events' => 0,
'by_severity' => [],
'by_event_type' => [],
'top_offending_ips' => [],
'failed_login_attempts' => 0,
'successful_logins' => 0
];
// 获取事件统计
$results = $wpdb->get_results($wpdb->prepare(
"SELECT
COUNT(*) as count,
severity,
event_type,
ip_address
FROM {$table_name}
WHERE DATE(created_at) = %s
GROUP BY severity, event_type, ip_address
ORDER BY count DESC",
$yesterday
));
foreach ($results as $row) {
$report_data['total_events'] += $row->count;
// 按严重性统计
if (!isset($report_data['by_severity'][$row->severity])) {
$report_data['by_severity'][$row->severity] = 0;
}
$report_data['by_severity'][$row->severity] += $row->count;
// 按事件类型统计
if (!isset($report_data['by_event_type'][$row->event_type])) {
$report_data['by_event_type'][$row->event_type] = 0;
}
$report_data['by_event_type'][$row->event_type] += $row->count;
// 统计特定事件
if ($row->event_type === 'login_failed') {
$report_data['failed_login_attempts'] += $row->count;
} elseif ($row->event_type === 'login_success') {
$report_data['successful_logins'] += $row->count;
}
// 收集攻击IP
if (in_array($row->event_type, ['login_failed', 'brute_force_attempt', 'suspicious_activity'])) {
if (!isset($report_data['top_offending_ips'][$row->ip_address])) {
$report_data['top_offending_ips'][$row->ip_address] = 0;
}
$report_data['top_offending_ips'][$row->ip_address] += $row->count;
}
}
// 排序并限制前10个攻击IP
arsort($report_data['top_offending_ips']);
$report_data['top_offending_ips'] = array_slice($report_data['top_offending_ips'], 0, 10, true);
return $report_data;
}
// 发送安全报告
public function send_security_report($report_data) {
$admin_email = get_option('admin_email');
$site_name = get_bloginfo('name');
$subject = sprintf(__('[%s] 每日安全报告 - %s', 'textdomain'),
$site_name,
$report_data['date']
);
// 构建报告内容
$message = $this->format_report_message($report_data);
// 添加HTML版本
$headers = ['Content-Type: text/html; charset=UTF-8'];
wp_mail($admin_email, $subject, $message, $headers);
}
// 格式化报告消息
private function format_report_message($report_data) {
ob_start();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; }
.report-container { max-width: 800px; margin: 0 auto; }
.section { margin: 20px 0; padding: 15px; background: #f9f9f9; border-left: 4px solid #0073aa; }
.critical { border-left-color: #dc3232; }
.high { border-left-color: #f56e28; }
.medium { border-left-color: #ffb900; }
.low { border-left-color: #46b450; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<div class="report-container">
<h1>安全报告 - <?php echo esc_html($report_data['date']); ?></h1>
<div class="section">
<h2>概览</h2>
<p>总安全事件: <strong><?php echo esc_html($report_data['total_events']); ?></strong></p>
<p>成功登录: <?php echo esc_html($report_data['successful_logins']); ?></p>
<p>失败登录尝试: <?php echo esc_html($report_data['failed_login_attempts']); ?></p>
</div>
<div class="section">
<h2>事件严重性分布</h2>
<table>
<tr>
<th>严重性</th>
<th>数量</th>
<th>百分比</th>
</tr>
<?php foreach ($report_data['by_severity'] as $severity => $count): ?>
<tr class="<?php echo esc_attr($severity); ?>">
<td><?php echo esc_html(ucfirst($severity)); ?></td>
