文章目录
-
- 在电子商务和在线交易日益普及的今天,支付回调接口作为连接支付平台与商户系统的关键桥梁,其安全性直接关系到资金安全和用户信任。特别是在WordPress开源系统中,由于其广泛的应用和开源特性,支付回调接口往往成为黑客攻击的重点目标。 支付回调接口一旦被攻破,可能导致虚假订单确认、资金盗取、用户数据泄露等严重后果。对于行业新人和程序员而言,理解并实施有效的安全加固措施,不仅是技术能力的体现,更是对用户和商户负责的职业态度。 本文将基于WordPress开源系统的代码开发,详细介绍6个实用的支付回调接口安全加固方法,帮助开发者构建更加安全可靠的支付系统。
-
- 支付回调接口的首要安全措施是验证请求是否确实来自合法的支付平台。在WordPress中,我们可以通过以下方式实现: /** * 验证支付平台签名 */ function validate_payment_signature($received_signature, $data, $secret_key) { // 按照支付平台要求的方式生成签名 $expected_signature = hash_hmac('sha256', $data, $secret_key); // 使用时间安全的字符串比较函数 return hash_equals($expected_signature, $received_signature); } /** * 处理支付回调 */ function handle_payment_callback() { // 获取支付平台传递的签名 $received_signature = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? ''; // 获取回调数据(注意:不要使用php://input读取后直接使用) $raw_data = file_get_contents('php://input'); $data = json_decode($raw_data, true); // 从数据库或配置中获取密钥 $secret_key = get_option('payment_secret_key'); // 验证签名 if (!validate_payment_signature($received_signature, $raw_data, $secret_key)) { error_log('支付回调签名验证失败: ' . date('Y-m-d H:i:s')); wp_die('签名验证失败', '支付回调错误', 403); } // 签名验证通过,继续处理业务逻辑 process_payment_success($data); }
- 同时,支付平台也需要确认回调接收方的合法性。这可以通过在回调URL中添加一次性令牌实现: /** * 生成带令牌的回调URL */ function generate_callback_url($order_id) { // 生成一次性令牌 $token = bin2hex(random_bytes(16)); // 将令牌与订单关联存储(有效期10分钟) set_transient('payment_callback_token_' . $order_id, $token, 10 * MINUTE_IN_SECONDS); // 构建回调URL $callback_url = add_query_arg( array( 'wc-api' => 'payment_callback', 'order_id' => $order_id, 'token' => $token ), home_url('/') ); return $callback_url; } /** * 验证回调令牌 */ function validate_callback_token($order_id, $received_token) { // 从临时存储中获取有效令牌 $valid_token = get_transient('payment_callback_token_' . $order_id); if (!$valid_token || !hash_equals($valid_token, $received_token)) { return false; } // 令牌使用后立即删除 delete_transient('payment_callback_token_' . $order_id); return true; }
-
- 大多数主流支付平台都会提供固定的IP地址或IP段用于回调请求。将这些IP地址加入白名单是有效的安全措施: /** * 支付平台IP白名单验证 */ function validate_callback_ip() { // 支付平台官方IP列表(示例,实际需根据支付平台文档配置) $whitelist_ips = array( '203.0.113.0/24', // 示例IP段 '198.51.100.10', // 示例单个IP '2001:db8::/32', // IPv6示例 ); $client_ip = get_client_ip_address(); foreach ($whitelist_ips as $allowed_ip) { if (ip_in_range($client_ip, $allowed_ip)) { return true; } } error_log('非法IP尝试访问支付回调接口: ' . $client_ip); return false; } /** * 获取客户端真实IP地址 */ function get_client_ip_address() { $ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'); foreach ($ip_keys as $key) { if (array_key_exists($key, $_SERVER) === true) { foreach (explode(',', $_SERVER[$key]) as $ip) { $ip = trim($ip); // 验证IP地址格式 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) { return $ip; } } } } return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } /** * 检查IP是否在指定范围内 */ function ip_in_range($ip, $range) { if (strpos($range, '/') === false) { // 单个IP比较 return $ip === $range; } // CIDR表示法处理 list($subnet, $bits) = explode('/', $range); // 将IP转换为整数 $ip = ip2long($ip); $subnet = ip2long($subnet); $mask = -1 << (32 - $bits); return ($ip & $mask) === ($subnet & $mask); }
- 在WordPress中,我们可以通过以下方式集成IP白名单验证: /** * 支付回调接口IP白名单中间件 */ class Payment_Callback_IP_Middleware { private $whitelist_ips; public function __construct() { // 从数据库或配置文件中读取IP白名单 $this->whitelist_ips = get_option('payment_callback_whitelist_ips', array()); // 添加默认的本地开发环境IP if (defined('WP_ENV') && WP_ENV === 'development') { $this->whitelist_ips[] = '127.0.0.1'; $this->whitelist_ips[] = '::1'; } } /** * 验证请求IP */ public function validate($request) { $client_ip = $this->get_client_ip(); foreach ($this->whitelist_ips as $allowed_ip) { if ($this->ip_in_range($client_ip, $allowed_ip)) { return true; } } // 记录安全日志 $this->log_security_event('ip_whitelist_violation', array( 'client_ip' => $client_ip, 'request_uri' => $_SERVER['REQUEST_URI'] ?? '', 'timestamp' => current_time('mysql') )); return false; } /** * 记录安全事件 */ private function log_security_event($event_type, $data) { $log_entry = array( 'event' => $event_type, 'data' => $data, 'timestamp' => current_time('timestamp') ); // 获取现有日志 $security_logs = get_option('payment_security_logs', array()); // 限制日志数量,保留最近1000条 $security_logs[] = $log_entry; if (count($security_logs) > 1000) { array_shift($security_logs); } update_option('payment_security_logs', $security_logs, false); } }
-
- 支付回调可能会因为网络问题被重复调用,幂等性设计确保同一笔交易无论被回调多少次,都只处理一次。这是支付系统可靠性的关键。 /** * 幂等性支付回调处理器 */ class Idempotent_Payment_Handler { private $order_id; private $transaction_id; public function __construct($order_id, $transaction_id) { $this->order_id = $order_id; $this->transaction_id = $transaction_id; } /** * 处理支付回调(幂等版本) */ public function process() { // 检查是否已处理过该交易 if ($this->is_already_processed()) { // 返回已处理的响应,避免重复处理 return $this->get_existing_response(); } // 获取数据库锁,防止并发处理 if (!$this->acquire_lock()) { // 获取锁失败,可能其他进程正在处理 return array( 'status' => 'processing', 'message' => '交易正在处理中' ); } try { // 处理支付成功逻辑 $result = $this->execute_payment_processing(); // 标记为已处理 $this->mark_as_processed($result); return $result; } finally { // 释放锁 $this->release_lock(); } } /** * 检查交易是否已处理 */ private function is_already_processed() { global $wpdb; $table_name = $wpdb->prefix . 'payment_transactions'; $query = $wpdb->prepare( "SELECT status, processed_at FROM {$table_name} WHERE transaction_id = %s AND order_id = %d", $this->transaction_id, $this->order_id ); $existing = $wpdb->get_row($query); return !empty($existing); } /** * 获取数据库锁 */ private function acquire_lock() { $lock_key = 'payment_lock_' . $this->order_id . '_' . $this->transaction_id; $lock_timeout = 30; // 30秒超时 // 使用WordPress瞬态API实现分布式锁 $lock_acquired = set_transient( $lock_key, time(), $lock_timeout ); return $lock_acquired; } /** * 执行支付处理逻辑 */ private function execute_payment_processing() { // 这里实现实际的支付处理逻辑 // 例如:更新订单状态、减少库存、发送通知等 $order = wc_get_order($this->order_id); if (!$order) { throw new Exception('订单不存在'); } // 检查订单是否已支付 if ($order->get_status() === 'processing' || $order->get_status() === 'completed') { return array( 'status' => 'success', 'message' => '订单已处理完成', 'order_status' => $order->get_status() ); } // 更新订单状态 $order->payment_complete($this->transaction_id); // 记录支付完成 $order->add_order_note( sprintf('支付成功,交易ID: %s', $this->transaction_id) ); return array( 'status' => 'success', 'message' => '支付处理完成', 'order_id' => $this->order_id, 'transaction_id' => $this->transaction_id ); } /** * 标记交易为已处理 */ private function mark_as_processed($result) { global $wpdb; $table_name = $wpdb->prefix . 'payment_transactions'; $wpdb->insert( $table_name, array( 'order_id' => $this->order_id, 'transaction_id' => $this->transaction_id, 'status' => 'completed', 'response_data' => maybe_serialize($result), 'processed_at' => current_time('mysql') ), array('%d', '%s', '%s', '%s', '%s') ); } /** * 释放锁 */ private function release_lock() { $lock_key = 'payment_lock_' . $this->order_id . '_' . $transaction_id; delete_transient($lock_key); } }
- 为了实现幂等性处理,我们需要在数据库中创建交易记录表: /** * 创建支付交易记录表 */ function create_payment_transactions_table() { global $wpdb; $table_name = $wpdb->prefix . 'payment_transactions'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS {$table_name} ( id bigint(20) NOT NULL AUTO_INCREMENT, order_id bigint(20) NOT NULL, transaction_id varchar(100) NOT NULL, status varchar(50) NOT NULL, response_data text, processed_at datetime DEFAULT CURRENT_TIMESTAMP, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY transaction_unique (transaction_id, order_id), KEY idx_order_id (order_id), KEY idx_processed_at (processed_at) ) {$charset_collate};"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } // 在插件激活时创建表 register_activation_hook(__FILE__, 'create_payment_transactions_table');
-
- 支付回调数据必须经过严格验证,防止注入攻击和非法数据: /** * 支付回调数据验证器 */ class Payment_Callback_Validator { /** * 验证并清理回调数据 */ public static function validate($input_data) { $rules = array( 'order_id' => array( 'required' => true, 'type' => 'integer', 'min' => 1, 'max' => 9999999999 ), 'transaction_id' => array( 'required' => true, 'type' => 'string', 'pattern' => '/^[a-zA-Z0-9_-]{10,50}$/', 'sanitize' => 'sanitize_text_field' ), 'amount' => array( 'required' => true, 'type' => 'numeric', 'min' => 0.01, 'max' => 1000000, 'precision' => 2 ), 'currency' => array( 'required' => true, 'type' => 'string', 'in' => array('CNY', 'USD', 'EUR', 'JPY', 'GBP') ), 'status' => array( 'required' => true, 'type' => 'string', 'in' => array('SUCCESS', 'FAILED', 'PENDING') ), 'timestamp' => array( 'required' => true, 'type' => 'datetime', 'format' => 'Y-m-d H:i:s' ) ); $validated_data = array(); $errors = array(); foreach ($rules as $field => $rule) { $value = $input_data[$field] ?? null; // 检查必填字段 if ($rule['required'] && ($value === null || $value === '')) { $errors[] = "字段 {$field} 是必填的"; continue; } // 如果字段非必填且为空,跳过验证 if (!$rule['required'] && ($value === null || $value === '')) { continue; } // 类型验证 switch ($rule['type']) { case 'integer': if (!is_numeric($value) || intval($value) != $value) { $errors[] = "字段 {$field} 必须是整数"; continue 2; } $value = intval($value); break; case 'numeric': if (!is_numeric($value)) { $errors[] = "字段 {$field} 必须是数字"; continue 2; } $value = floatval($value); break; case 'string': if (!is_string($value)) { $errors[] = "字段 {$field} 必须是字符串"; continue 2; } break; case 'datetime': $datetime = DateTime::createFromFormat($rule['format'], $value); if (!$datetime || $datetime->format($rule['format']) !== $value) { $errors[] = "字段 {$field} 格式不正确,应为 {$rule['format']}"; continue 2; } break; } // 范围验证 if (isset($rule['min']) && $value < $rule['min']) { $errors[] = "字段 {$field} 不能小于 {$rule['min']}"; continue; } if (isset($rule['max']) && $value > $rule['max']) { $errors[] = "字段 {$field} 不能大于 {$rule['max']}"; continue; } // 枚举值验证 if (isset($rule['in']) && !in_array($value, $rule['in'])) { $errors[] = "字段 {$field} 的值无效"; continue; } // 正则验证 $errors[] = "字段 {$field} 格式不正确"; continue; } } // 精度处理(针对金额) if (isset($rule['precision'])) { $value = round($value, $rule['precision']); } // 数据清理 if (isset($rule['sanitize'])) { switch ($rule['sanitize']) { case 'sanitize_text_field': $value = sanitize_text_field($value); break; case 'sanitize_email': $value = sanitize_email($value); break; case 'esc_url': $value = esc_url_raw($value); break; } } $validated_data[$field] = $value; } if (!empty($errors)) { throw new Validation_Exception('数据验证失败: ' . implode(', ', $errors)); } return $validated_data; } /** * 验证金额一致性 */ public static function validate_amount_consistency($callback_amount, $order_amount, $currency) { // 允许的误差范围(考虑汇率浮动和手续费) $tolerance = 0.01; if (abs($callback_amount - $order_amount) > $tolerance) { error_log(sprintf( '金额不一致: 回调金额=%s, 订单金额=%s, 货币=%s', $callback_amount, $order_amount, $currency )); return false; } return true; } } /** * 自定义验证异常类 */ class Validation_Exception extends Exception { private $validation_errors; public function __construct($message, $errors = array()) { parent::__construct($message); $this->validation_errors = $errors; } public function getValidationErrors() { return $this->validation_errors; } }
- 在处理支付回调前,必须验证订单状态的合法性: /** * 订单状态验证器 */ class Order_State_Validator { /** * 验证订单是否可接受支付 */ public static function validate_for_payment($order_id, $expected_amount) { $order = wc_get_order($order_id); if (!$order) { throw new Exception('订单不存在'); } // 检查订单状态 $current_status = $order->get_status(); $allowed_statuses = array('pending', 'on-hold', 'failed'); if (!in_array($current_status, $allowed_statuses)) { throw new Exception(sprintf( '订单状态不可支付。当前状态: %s', $current_status )); } // 验证订单金额 $order_total = $order->get_total(); if (!Payment_Callback_Validator::validate_amount_consistency( $expected_amount, $order_total, $order->get_currency() )) { throw new Exception('支付金额与订单金额不一致'); } // 检查订单是否已过期 $order_date = $order->get_date_created(); $expiry_hours = 24; // 订单有效期24小时 $expiry_time = $order_date->modify("+{$expiry_hours} hours"); if (current_time('timestamp') > $expiry_time->getTimestamp()) { throw new Exception('订单已过期'); } return true; } /** * 验证订单是否属于当前用户(如果需要) */ public static function validate_order_ownership($order_id, $user_id = null) { if ($user_id === null) { $user_id = get_current_user_id(); } $order = wc_get_order($order_id); if (!$order) { return false; } $order_user_id = $order->get_user_id(); // 允许未登录用户通过其他方式验证(如订单密钥) if ($order_user_id == 0) { return self::validate_guest_order($order_id); } return $order_user_id == $user_id; } /** * 验证访客订单 */ private static function validate_guest_order($order_id) { // 这里可以实现访客订单的验证逻辑 // 例如:检查订单密钥、验证邮箱等 return true; } }
-
- 完善的日志系统是安全审计和故障排查的基础: /** * 支付安全日志系统 */ class Payment_Security_Logger { const LOG_LEVEL_DEBUG = 'debug'; const LOG_LEVEL_INFO = 'info'; const LOG_LEVEL_WARNING = 'warning'; const LOG_LEVEL_ERROR = 'error'; const LOG_LEVEL_CRITICAL = 'critical'; private $log_table; public function __construct() { global $wpdb; $this->log_table = $wpdb->prefix . 'payment_security_logs'; } /** * 记录支付回调日志 */ public function log_callback($level, $message, $context = array()) { $log_entry = array( 'level' => $level, 'message' => $this->interpolate($message, $context), 'context' => maybe_serialize($context), 'ip_address' => $this->get_client_ip(), 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'request_url' => $_SERVER['REQUEST_URI'] ?? '', 'referrer' => $_SERVER['HTTP_REFERER'] ?? '', 'created_at' => current_time('mysql') ); // 根据日志级别决定是否记录详细信息 if (in_array($level, [self::LOG_LEVEL_ERROR, self::LOG_LEVEL_CRITICAL])) { $log_entry['request_body'] = $this->get_sanitized_request_body(); $log_entry['headers'] = maybe_serialize($this->get_sanitized_headers()); } $this->save_to_database($log_entry); $this->write_to_file($log_entry); // 关键错误发送警报 if ($level === self::LOG_LEVEL_CRITICAL) { $this->send_alert($log_entry); } } /** * 保存到数据库 */ private function save_to_database($log_entry) { global $wpdb; $wpdb->insert( $this->log_table, $log_entry, array('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ); // 定期清理旧日志(保留30天) $this->cleanup_old_logs(); } /** * 写入文件日志 */ private function write_to_file($log_entry) { $log_dir = WP_CONTENT_DIR . '/payment-logs/'; if (!file_exists($log_dir)) { wp_mkdir_p($log_dir); } // 按日期分文件 $log_file = $log_dir . 'payment-' . date('Y-m-d') . '.log'; $log_line = sprintf( "[%s] %s: %s %sn", $log_entry['created_at'], strtoupper($log_entry['level']), $log_entry['message'], !empty($log_entry['context']) ? json_encode(unserialize($log_entry['context'])) : '' ); file_put_contents($log_file, $log_line, FILE_APPEND | LOCK_EX); } /** * 发送安全警报 */ private function send_alert($log_entry) { $admin_email = get_option('admin_email'); $site_name = get_bloginfo('name'); $subject = sprintf('[%s] 支付安全警报 - %s', $site_name, date('Y-m-d H:i:s') ); $message = sprintf( "安全警报详情:nn" . "时间: %sn" . "级别: %sn" . "消息: %sn" . "IP地址: %sn" . "请求URL: %snn" . "请立即检查系统安全。nn" . "此邮件由系统自动发送,请勿回复。", $log_entry['created_at'], $log_entry['level'], $log_entry['message'], $log_entry['ip_address'], $log_entry['request_url'] ); wp_mail($admin_email, $subject, $message); } /** * 清理旧日志 */ private function cleanup_old_logs() { global $wpdb; $retention_days = 30; $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$retention_days} days")); $wpdb->query( $wpdb->prepare( "DELETE FROM {$this->log_table} WHERE created_at < %s", $cutoff_date ) ); } /** * 获取清理后的请求体 */ private function get_sanitized_request_body() { $raw_body = file_get_contents('php://input'); // 移除敏感信息(如信用卡号、CVV等) $patterns = array( '/"card_number"s*:s*"[^"]*"/i' => '"card_number":"[REDACTED]"', '/"cvv"s*:s*"[^"]*"/i' => '"cvv":"[REDACTED]"', '/"password"s*:s*"[^"]*"/i' => '"password":"[REDACTED]"', ); foreach ($patterns as $pattern => $replacement) { $raw_body = preg_replace($pattern, $replacement, $raw_body); } return substr($raw_body, 0, 10000); // 限制长度 } /** * 获取清理后的请求头 */ private function get_sanitized_headers() { $headers = array(); foreach ($_SERVER as $key => $value) { if (strpos($key, 'HTTP_') === 0) { $header_key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); // 移除敏感头信息 if (!in_array($header_key, ['Authorization', 'Cookie', 'X-Api-Key'])) { $headers[$header_key] = $value; } } } return $headers; } /** * 消息模板替换 */ private function interpolate($message, $context) { $replace = array(); foreach ($context as $key => $val) { $replace['{' . $key . '}'] = $val; } return strtr($message, $replace); } }
- /** * 支付接口监控系统 */ class Payment_Monitor { private $logger; public function __construct() { $this->logger = new Payment_Security_Logger(); } /** * 监控支付回调频率 */ public function monitor_callback_frequency($order_id, $threshold = 10) { global $wpdb; $table_name = $wpdb->prefix . 'payment_callback_logs'; $time_window = '5 MINUTE'; // 5分钟时间窗口 $query = $wpdb->prepare( "SELECT COUNT(*) as count FROM {$table_name} WHERE order_id = %d AND created_at > DATE_SUB(NOW(), INTERVAL {$time_window})", $order_id ); $result = $wpdb->get_var($query); if ($result >= $threshold) { $this->logger->log_callback( Payment_Security_Logger::LOG_LEVEL_WARNING, '支付回调频率异常: 订单 {order_id} 在 {time_window} 内收到 {count} 次回调', array( 'order_id' => $order_id, 'time_window' => $time_window, 'count' => $result ) ); // 触发频率限制 $this->rate_limit_order($order_id); return false; } return true; } /** * 订单频率限制 */ private function rate_limit_order($order_id) { $lock_key = 'rate_limit_' . $order_id; $lock_time = 15 * MINUTE_IN_SECONDS; // 锁定15分钟 set_transient($lock_key, true, $lock_time); $this->logger->log_callback( Payment_Security_Logger::LOG_LEVEL_INFO, '订单 {order_id} 已被频率限制,锁定 {minutes} 分钟', array( 'order_id' => $order_id, 'minutes' => 15 ) ); } /** * 检查异常模式 */ public function detect_anomalies() { global $wpdb; $table_name = $wpdb->prefix . 'payment_security_logs'; // 检测短时间内大量错误 $query = " SELECT COUNT(*) as error_count, ip_address FROM {$table_name} WHERE level IN ('error', 'critical') AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR) GROUP BY ip_address HAVING error_count > 20 "; $results = $wpdb->get_results($query); foreach ($results as $row) { $this->logger->log_callback( Payment_Security_Logger::LOG_LEVEL_CRITICAL, '检测到异常攻击模式: IP {ip} 在1小时内触发 {count} 次错误', array( 'ip' => $row->ip_address, 'count' => $row->error_count ) ); // 自动封禁恶意IP $this->block_ip($row->ip_address); } } /** * 封禁IP地址 */ private function block_ip($ip_address) { $blocked_ips = get_option('payment_blocked_ips', array()); if (!in_array($ip_address, $blocked_ips)) { $blocked_ips[] = $ip_address; update_option('payment_blocked_ips', $blocked_ips); $this->logger->log_callback( Payment_Security_Logger::LOG_LEVEL_WARNING, 'IP地址 {ip} 已被自动封禁', array('ip' => $ip_address) ); } } }
在电子商务和在线交易日益普及的今天,支付回调接口作为连接支付平台与商户系统的关键桥梁,其安全性直接关系到资金安全和用户信任。特别是在WordPress开源系统中,由于其广泛的应用和开源特性,支付回调接口往往成为黑客攻击的重点目标。
支付回调接口一旦被攻破,可能导致虚假订单确认、资金盗取、用户数据泄露等严重后果。对于行业新人和程序员而言,理解并实施有效的安全加固措施,不仅是技术能力的体现,更是对用户和商户负责的职业态度。
本文将基于WordPress开源系统的代码开发,详细介绍6个实用的支付回调接口安全加固方法,帮助开发者构建更加安全可靠的支付系统。
支付回调接口的首要安全措施是验证请求是否确实来自合法的支付平台。在WordPress中,我们可以通过以下方式实现:
/**
* 验证支付平台签名
*/
function validate_payment_signature($received_signature, $data, $secret_key) {
// 按照支付平台要求的方式生成签名
$expected_signature = hash_hmac('sha256', $data, $secret_key);
// 使用时间安全的字符串比较函数
return hash_equals($expected_signature, $received_signature);
}
/**
* 处理支付回调
*/
function handle_payment_callback() {
// 获取支付平台传递的签名
$received_signature = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? '';
// 获取回调数据(注意:不要使用php://input读取后直接使用)
$raw_data = file_get_contents('php://input');
$data = json_decode($raw_data, true);
// 从数据库或配置中获取密钥
$secret_key = get_option('payment_secret_key');
// 验证签名
if (!validate_payment_signature($received_signature, $raw_data, $secret_key)) {
error_log('支付回调签名验证失败: ' . date('Y-m-d H:i:s'));
wp_die('签名验证失败', '支付回调错误', 403);
}
// 签名验证通过,继续处理业务逻辑
process_payment_success($data);
}
同时,支付平台也需要确认回调接收方的合法性。这可以通过在回调URL中添加一次性令牌实现:
/**
* 生成带令牌的回调URL
*/
function generate_callback_url($order_id) {
// 生成一次性令牌
$token = bin2hex(random_bytes(16));
// 将令牌与订单关联存储(有效期10分钟)
set_transient('payment_callback_token_' . $order_id, $token, 10 * MINUTE_IN_SECONDS);
// 构建回调URL
$callback_url = add_query_arg(
array(
'wc-api' => 'payment_callback',
'order_id' => $order_id,
'token' => $token
),
home_url('/')
);
return $callback_url;
}
/**
* 验证回调令牌
*/
function validate_callback_token($order_id, $received_token) {
// 从临时存储中获取有效令牌
$valid_token = get_transient('payment_callback_token_' . $order_id);
if (!$valid_token || !hash_equals($valid_token, $received_token)) {
return false;
}
// 令牌使用后立即删除
delete_transient('payment_callback_token_' . $order_id);
return true;
}
大多数主流支付平台都会提供固定的IP地址或IP段用于回调请求。将这些IP地址加入白名单是有效的安全措施:
/**
* 支付平台IP白名单验证
*/
function validate_callback_ip() {
// 支付平台官方IP列表(示例,实际需根据支付平台文档配置)
$whitelist_ips = array(
'203.0.113.0/24', // 示例IP段
'198.51.100.10', // 示例单个IP
'2001:db8::/32', // IPv6示例
);
$client_ip = get_client_ip_address();
foreach ($whitelist_ips as $allowed_ip) {
if (ip_in_range($client_ip, $allowed_ip)) {
return true;
}
}
error_log('非法IP尝试访问支付回调接口: ' . $client_ip);
return false;
}
/**
* 获取客户端真实IP地址
*/
function get_client_ip_address() {
$ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
foreach ($ip_keys as $key) {
if (array_key_exists($key, $_SERVER) === true) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
$ip = trim($ip);
// 验证IP地址格式
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
return $ip;
}
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
/**
* 检查IP是否在指定范围内
*/
function ip_in_range($ip, $range) {
if (strpos($range, '/') === false) {
// 单个IP比较
return $ip === $range;
}
// CIDR表示法处理
list($subnet, $bits) = explode('/', $range);
// 将IP转换为整数
$ip = ip2long($ip);
$subnet = ip2long($subnet);
$mask = -1 << (32 - $bits);
return ($ip & $mask) === ($subnet & $mask);
}
在WordPress中,我们可以通过以下方式集成IP白名单验证:
/**
* 支付回调接口IP白名单中间件
*/
class Payment_Callback_IP_Middleware {
private $whitelist_ips;
public function __construct() {
// 从数据库或配置文件中读取IP白名单
$this->whitelist_ips = get_option('payment_callback_whitelist_ips', array());
// 添加默认的本地开发环境IP
if (defined('WP_ENV') && WP_ENV === 'development') {
$this->whitelist_ips[] = '127.0.0.1';
$this->whitelist_ips[] = '::1';
}
}
/**
* 验证请求IP
*/
public function validate($request) {
$client_ip = $this->get_client_ip();
foreach ($this->whitelist_ips as $allowed_ip) {
if ($this->ip_in_range($client_ip, $allowed_ip)) {
return true;
}
}
// 记录安全日志
$this->log_security_event('ip_whitelist_violation', array(
'client_ip' => $client_ip,
'request_uri' => $_SERVER['REQUEST_URI'] ?? '',
'timestamp' => current_time('mysql')
));
return false;
}
/**
* 记录安全事件
*/
private function log_security_event($event_type, $data) {
$log_entry = array(
'event' => $event_type,
'data' => $data,
'timestamp' => current_time('timestamp')
);
// 获取现有日志
$security_logs = get_option('payment_security_logs', array());
// 限制日志数量,保留最近1000条
$security_logs[] = $log_entry;
if (count($security_logs) > 1000) {
array_shift($security_logs);
}
update_option('payment_security_logs', $security_logs, false);
}
}
支付回调可能会因为网络问题被重复调用,幂等性设计确保同一笔交易无论被回调多少次,都只处理一次。这是支付系统可靠性的关键。
/**
* 幂等性支付回调处理器
*/
class Idempotent_Payment_Handler {
private $order_id;
private $transaction_id;
public function __construct($order_id, $transaction_id) {
$this->order_id = $order_id;
$this->transaction_id = $transaction_id;
}
/**
* 处理支付回调(幂等版本)
*/
public function process() {
// 检查是否已处理过该交易
if ($this->is_already_processed()) {
// 返回已处理的响应,避免重复处理
return $this->get_existing_response();
}
// 获取数据库锁,防止并发处理
if (!$this->acquire_lock()) {
// 获取锁失败,可能其他进程正在处理
return array(
'status' => 'processing',
'message' => '交易正在处理中'
);
}
try {
// 处理支付成功逻辑
$result = $this->execute_payment_processing();
// 标记为已处理
$this->mark_as_processed($result);
return $result;
} finally {
// 释放锁
$this->release_lock();
}
}
/**
* 检查交易是否已处理
*/
private function is_already_processed() {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_transactions';
$query = $wpdb->prepare(
"SELECT status, processed_at FROM {$table_name}
WHERE transaction_id = %s AND order_id = %d",
$this->transaction_id,
$this->order_id
);
$existing = $wpdb->get_row($query);
return !empty($existing);
}
/**
* 获取数据库锁
*/
private function acquire_lock() {
$lock_key = 'payment_lock_' . $this->order_id . '_' . $this->transaction_id;
$lock_timeout = 30; // 30秒超时
// 使用WordPress瞬态API实现分布式锁
$lock_acquired = set_transient(
$lock_key,
time(),
$lock_timeout
);
return $lock_acquired;
}
/**
* 执行支付处理逻辑
*/
private function execute_payment_processing() {
// 这里实现实际的支付处理逻辑
// 例如:更新订单状态、减少库存、发送通知等
$order = wc_get_order($this->order_id);
if (!$order) {
throw new Exception('订单不存在');
}
// 检查订单是否已支付
if ($order->get_status() === 'processing' || $order->get_status() === 'completed') {
return array(
'status' => 'success',
'message' => '订单已处理完成',
'order_status' => $order->get_status()
);
}
// 更新订单状态
$order->payment_complete($this->transaction_id);
// 记录支付完成
$order->add_order_note(
sprintf('支付成功,交易ID: %s', $this->transaction_id)
);
return array(
'status' => 'success',
'message' => '支付处理完成',
'order_id' => $this->order_id,
'transaction_id' => $this->transaction_id
);
}
/**
* 标记交易为已处理
*/
private function mark_as_processed($result) {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_transactions';
$wpdb->insert(
$table_name,
array(
'order_id' => $this->order_id,
'transaction_id' => $this->transaction_id,
'status' => 'completed',
'response_data' => maybe_serialize($result),
'processed_at' => current_time('mysql')
),
array('%d', '%s', '%s', '%s', '%s')
);
}
/**
* 释放锁
*/
private function release_lock() {
$lock_key = 'payment_lock_' . $this->order_id . '_' . $transaction_id;
delete_transient($lock_key);
}
}
为了实现幂等性处理,我们需要在数据库中创建交易记录表:
/**
* 创建支付交易记录表
*/
function create_payment_transactions_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_transactions';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
id bigint(20) NOT NULL AUTO_INCREMENT,
order_id bigint(20) NOT NULL,
transaction_id varchar(100) NOT NULL,
status varchar(50) NOT NULL,
response_data text,
processed_at datetime DEFAULT CURRENT_TIMESTAMP,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY transaction_unique (transaction_id, order_id),
KEY idx_order_id (order_id),
KEY idx_processed_at (processed_at)
) {$charset_collate};";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// 在插件激活时创建表
register_activation_hook(__FILE__, 'create_payment_transactions_table');
支付回调数据必须经过严格验证,防止注入攻击和非法数据:
/**
* 支付回调数据验证器
*/
class Payment_Callback_Validator {
/**
* 验证并清理回调数据
*/
public static function validate($input_data) {
$rules = array(
'order_id' => array(
'required' => true,
'type' => 'integer',
'min' => 1,
'max' => 9999999999
),
'transaction_id' => array(
'required' => true,
'type' => 'string',
'pattern' => '/^[a-zA-Z0-9_-]{10,50}$/',
'sanitize' => 'sanitize_text_field'
),
'amount' => array(
'required' => true,
'type' => 'numeric',
'min' => 0.01,
'max' => 1000000,
'precision' => 2
),
'currency' => array(
'required' => true,
'type' => 'string',
'in' => array('CNY', 'USD', 'EUR', 'JPY', 'GBP')
),
'status' => array(
'required' => true,
'type' => 'string',
'in' => array('SUCCESS', 'FAILED', 'PENDING')
),
'timestamp' => array(
'required' => true,
'type' => 'datetime',
'format' => 'Y-m-d H:i:s'
)
);
$validated_data = array();
$errors = array();
foreach ($rules as $field => $rule) {
$value = $input_data[$field] ?? null;
// 检查必填字段
if ($rule['required'] && ($value === null || $value === '')) {
$errors[] = "字段 {$field} 是必填的";
continue;
}
// 如果字段非必填且为空,跳过验证
if (!$rule['required'] && ($value === null || $value === '')) {
continue;
}
// 类型验证
switch ($rule['type']) {
case 'integer':
if (!is_numeric($value) || intval($value) != $value) {
$errors[] = "字段 {$field} 必须是整数";
continue 2;
}
$value = intval($value);
break;
case 'numeric':
if (!is_numeric($value)) {
$errors[] = "字段 {$field} 必须是数字";
continue 2;
}
$value = floatval($value);
break;
case 'string':
if (!is_string($value)) {
$errors[] = "字段 {$field} 必须是字符串";
continue 2;
}
break;
case 'datetime':
$datetime = DateTime::createFromFormat($rule['format'], $value);
if (!$datetime || $datetime->format($rule['format']) !== $value) {
$errors[] = "字段 {$field} 格式不正确,应为 {$rule['format']}";
continue 2;
}
break;
}
// 范围验证
if (isset($rule['min']) && $value < $rule['min']) {
$errors[] = "字段 {$field} 不能小于 {$rule['min']}";
continue;
}
if (isset($rule['max']) && $value > $rule['max']) {
$errors[] = "字段 {$field} 不能大于 {$rule['max']}";
continue;
}
// 枚举值验证
if (isset($rule['in']) && !in_array($value, $rule['in'])) {
$errors[] = "字段 {$field} 的值无效";
continue;
}
// 正则验证
$errors[] = "字段 {$field} 格式不正确";
continue;
}
}
// 精度处理(针对金额)
if (isset($rule['precision'])) {
$value = round($value, $rule['precision']);
}
// 数据清理
if (isset($rule['sanitize'])) {
switch ($rule['sanitize']) {
case 'sanitize_text_field':
$value = sanitize_text_field($value);
break;
case 'sanitize_email':
$value = sanitize_email($value);
break;
case 'esc_url':
$value = esc_url_raw($value);
break;
}
}
$validated_data[$field] = $value;
}
if (!empty($errors)) {
throw new Validation_Exception('数据验证失败: ' . implode(', ', $errors));
}
return $validated_data;
}
/**
* 验证金额一致性
*/
public static function validate_amount_consistency($callback_amount, $order_amount, $currency) {
// 允许的误差范围(考虑汇率浮动和手续费)
$tolerance = 0.01;
if (abs($callback_amount - $order_amount) > $tolerance) {
error_log(sprintf(
'金额不一致: 回调金额=%s, 订单金额=%s, 货币=%s',
$callback_amount,
$order_amount,
$currency
));
return false;
}
return true;
}
}
/**
* 自定义验证异常类
*/
class Validation_Exception extends Exception {
private $validation_errors;
public function __construct($message, $errors = array()) {
parent::__construct($message);
$this->validation_errors = $errors;
}
public function getValidationErrors() {
return $this->validation_errors;
}
}
在处理支付回调前,必须验证订单状态的合法性:
/**
* 订单状态验证器
*/
class Order_State_Validator {
/**
* 验证订单是否可接受支付
*/
public static function validate_for_payment($order_id, $expected_amount) {
$order = wc_get_order($order_id);
if (!$order) {
throw new Exception('订单不存在');
}
// 检查订单状态
$current_status = $order->get_status();
$allowed_statuses = array('pending', 'on-hold', 'failed');
if (!in_array($current_status, $allowed_statuses)) {
throw new Exception(sprintf(
'订单状态不可支付。当前状态: %s',
$current_status
));
}
// 验证订单金额
$order_total = $order->get_total();
if (!Payment_Callback_Validator::validate_amount_consistency(
$expected_amount,
$order_total,
$order->get_currency()
)) {
throw new Exception('支付金额与订单金额不一致');
}
// 检查订单是否已过期
$order_date = $order->get_date_created();
$expiry_hours = 24; // 订单有效期24小时
$expiry_time = $order_date->modify("+{$expiry_hours} hours");
if (current_time('timestamp') > $expiry_time->getTimestamp()) {
throw new Exception('订单已过期');
}
return true;
}
/**
* 验证订单是否属于当前用户(如果需要)
*/
public static function validate_order_ownership($order_id, $user_id = null) {
if ($user_id === null) {
$user_id = get_current_user_id();
}
$order = wc_get_order($order_id);
if (!$order) {
return false;
}
$order_user_id = $order->get_user_id();
// 允许未登录用户通过其他方式验证(如订单密钥)
if ($order_user_id == 0) {
return self::validate_guest_order($order_id);
}
return $order_user_id == $user_id;
}
/**
* 验证访客订单
*/
private static function validate_guest_order($order_id) {
// 这里可以实现访客订单的验证逻辑
// 例如:检查订单密钥、验证邮箱等
return true;
}
}
完善的日志系统是安全审计和故障排查的基础:
/**
* 支付安全日志系统
*/
class Payment_Security_Logger {
const LOG_LEVEL_DEBUG = 'debug';
const LOG_LEVEL_INFO = 'info';
const LOG_LEVEL_WARNING = 'warning';
const LOG_LEVEL_ERROR = 'error';
const LOG_LEVEL_CRITICAL = 'critical';
private $log_table;
public function __construct() {
global $wpdb;
$this->log_table = $wpdb->prefix . 'payment_security_logs';
}
/**
* 记录支付回调日志
*/
public function log_callback($level, $message, $context = array()) {
$log_entry = array(
'level' => $level,
'message' => $this->interpolate($message, $context),
'context' => maybe_serialize($context),
'ip_address' => $this->get_client_ip(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'request_url' => $_SERVER['REQUEST_URI'] ?? '',
'referrer' => $_SERVER['HTTP_REFERER'] ?? '',
'created_at' => current_time('mysql')
);
// 根据日志级别决定是否记录详细信息
if (in_array($level, [self::LOG_LEVEL_ERROR, self::LOG_LEVEL_CRITICAL])) {
$log_entry['request_body'] = $this->get_sanitized_request_body();
$log_entry['headers'] = maybe_serialize($this->get_sanitized_headers());
}
$this->save_to_database($log_entry);
$this->write_to_file($log_entry);
// 关键错误发送警报
if ($level === self::LOG_LEVEL_CRITICAL) {
$this->send_alert($log_entry);
}
}
/**
* 保存到数据库
*/
private function save_to_database($log_entry) {
global $wpdb;
$wpdb->insert(
$this->log_table,
$log_entry,
array('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')
);
// 定期清理旧日志(保留30天)
$this->cleanup_old_logs();
}
/**
* 写入文件日志
*/
private function write_to_file($log_entry) {
$log_dir = WP_CONTENT_DIR . '/payment-logs/';
if (!file_exists($log_dir)) {
wp_mkdir_p($log_dir);
}
// 按日期分文件
$log_file = $log_dir . 'payment-' . date('Y-m-d') . '.log';
$log_line = sprintf(
"[%s] %s: %s %sn",
$log_entry['created_at'],
strtoupper($log_entry['level']),
$log_entry['message'],
!empty($log_entry['context']) ? json_encode(unserialize($log_entry['context'])) : ''
);
file_put_contents($log_file, $log_line, FILE_APPEND | LOCK_EX);
}
/**
* 发送安全警报
*/
private function send_alert($log_entry) {
$admin_email = get_option('admin_email');
$site_name = get_bloginfo('name');
$subject = sprintf('[%s] 支付安全警报 - %s',
$site_name,
date('Y-m-d H:i:s')
);
$message = sprintf(
"安全警报详情:nn" .
"时间: %sn" .
"级别: %sn" .
"消息: %sn" .
"IP地址: %sn" .
"请求URL: %snn" .
"请立即检查系统安全。nn" .
"此邮件由系统自动发送,请勿回复。",
$log_entry['created_at'],
$log_entry['level'],
$log_entry['message'],
$log_entry['ip_address'],
$log_entry['request_url']
);
wp_mail($admin_email, $subject, $message);
}
/**
* 清理旧日志
*/
private function cleanup_old_logs() {
global $wpdb;
$retention_days = 30;
$cutoff_date = date('Y-m-d H:i:s', strtotime("-{$retention_days} days"));
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$this->log_table} WHERE created_at < %s",
$cutoff_date
)
);
}
/**
* 获取清理后的请求体
*/
private function get_sanitized_request_body() {
$raw_body = file_get_contents('php://input');
// 移除敏感信息(如信用卡号、CVV等)
$patterns = array(
'/"card_number"s*:s*"[^"]*"/i' => '"card_number":"[REDACTED]"',
'/"cvv"s*:s*"[^"]*"/i' => '"cvv":"[REDACTED]"',
'/"password"s*:s*"[^"]*"/i' => '"password":"[REDACTED]"',
);
foreach ($patterns as $pattern => $replacement) {
$raw_body = preg_replace($pattern, $replacement, $raw_body);
}
return substr($raw_body, 0, 10000); // 限制长度
}
/**
* 获取清理后的请求头
*/
private function get_sanitized_headers() {
$headers = array();
foreach ($_SERVER as $key => $value) {
if (strpos($key, 'HTTP_') === 0) {
$header_key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))));
// 移除敏感头信息
if (!in_array($header_key, ['Authorization', 'Cookie', 'X-Api-Key'])) {
$headers[$header_key] = $value;
}
}
}
return $headers;
}
/**
* 消息模板替换
*/
private function interpolate($message, $context) {
$replace = array();
foreach ($context as $key => $val) {
$replace['{' . $key . '}'] = $val;
}
return strtr($message, $replace);
}
}
/**
* 支付接口监控系统
*/
class Payment_Monitor {
private $logger;
public function __construct() {
$this->logger = new Payment_Security_Logger();
}
/**
* 监控支付回调频率
*/
public function monitor_callback_frequency($order_id, $threshold = 10) {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_callback_logs';
$time_window = '5 MINUTE'; // 5分钟时间窗口
$query = $wpdb->prepare(
"SELECT COUNT(*) as count
FROM {$table_name}
WHERE order_id = %d
AND created_at > DATE_SUB(NOW(), INTERVAL {$time_window})",
$order_id
);
$result = $wpdb->get_var($query);
if ($result >= $threshold) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'支付回调频率异常: 订单 {order_id} 在 {time_window} 内收到 {count} 次回调',
array(
'order_id' => $order_id,
'time_window' => $time_window,
'count' => $result
)
);
// 触发频率限制
$this->rate_limit_order($order_id);
return false;
}
return true;
}
/**
* 订单频率限制
*/
private function rate_limit_order($order_id) {
$lock_key = 'rate_limit_' . $order_id;
$lock_time = 15 * MINUTE_IN_SECONDS; // 锁定15分钟
set_transient($lock_key, true, $lock_time);
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_INFO,
'订单 {order_id} 已被频率限制,锁定 {minutes} 分钟',
array(
'order_id' => $order_id,
'minutes' => 15
)
);
}
/**
* 检查异常模式
*/
public function detect_anomalies() {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_security_logs';
// 检测短时间内大量错误
$query = "
SELECT COUNT(*) as error_count, ip_address
FROM {$table_name}
WHERE level IN ('error', 'critical')
AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY ip_address
HAVING error_count > 20
";
$results = $wpdb->get_results($query);
foreach ($results as $row) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_CRITICAL,
'检测到异常攻击模式: IP {ip} 在1小时内触发 {count} 次错误',
array(
'ip' => $row->ip_address,
'count' => $row->error_count
)
);
// 自动封禁恶意IP
$this->block_ip($row->ip_address);
}
}
/**
* 封禁IP地址
*/
private function block_ip($ip_address) {
$blocked_ips = get_option('payment_blocked_ips', array());
if (!in_array($ip_address, $blocked_ips)) {
$blocked_ips[] = $ip_address;
update_option('payment_blocked_ips', $blocked_ips);
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'IP地址 {ip} 已被自动封禁',
array('ip' => $ip_address)
);
}
}
}
/**
* 支付接口监控系统
*/
class Payment_Monitor {
private $logger;
public function __construct() {
$this->logger = new Payment_Security_Logger();
}
/**
* 监控支付回调频率
*/
public function monitor_callback_frequency($order_id, $threshold = 10) {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_callback_logs';
$time_window = '5 MINUTE'; // 5分钟时间窗口
$query = $wpdb->prepare(
"SELECT COUNT(*) as count
FROM {$table_name}
WHERE order_id = %d
AND created_at > DATE_SUB(NOW(), INTERVAL {$time_window})",
$order_id
);
$result = $wpdb->get_var($query);
if ($result >= $threshold) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'支付回调频率异常: 订单 {order_id} 在 {time_window} 内收到 {count} 次回调',
array(
'order_id' => $order_id,
'time_window' => $time_window,
'count' => $result
)
);
// 触发频率限制
$this->rate_limit_order($order_id);
return false;
}
return true;
}
/**
* 订单频率限制
*/
private function rate_limit_order($order_id) {
$lock_key = 'rate_limit_' . $order_id;
$lock_time = 15 * MINUTE_IN_SECONDS; // 锁定15分钟
set_transient($lock_key, true, $lock_time);
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_INFO,
'订单 {order_id} 已被频率限制,锁定 {minutes} 分钟',
array(
'order_id' => $order_id,
'minutes' => 15
)
);
}
/**
* 检查异常模式
*/
public function detect_anomalies() {
global $wpdb;
$table_name = $wpdb->prefix . 'payment_security_logs';
// 检测短时间内大量错误
$query = "
SELECT COUNT(*) as error_count, ip_address
FROM {$table_name}
WHERE level IN ('error', 'critical')
AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY ip_address
HAVING error_count > 20
";
$results = $wpdb->get_results($query);
foreach ($results as $row) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_CRITICAL,
'检测到异常攻击模式: IP {ip} 在1小时内触发 {count} 次错误',
array(
'ip' => $row->ip_address,
'count' => $row->error_count
)
);
// 自动封禁恶意IP
$this->block_ip($row->ip_address);
}
}
/**
* 封禁IP地址
*/
private function block_ip($ip_address) {
$blocked_ips = get_option('payment_blocked_ips', array());
if (!in_array($ip_address, $blocked_ips)) {
$blocked_ips[] = $ip_address;
update_option('payment_blocked_ips', $blocked_ips);
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'IP地址 {ip} 已被自动封禁',
array('ip' => $ip_address)
);
}
}
}
/**
* 支付回调异常处理器
*/
class Payment_Exception_Handler {
private $logger;
public function __construct() {
$this->logger = new Payment_Security_Logger();
}
/**
* 处理支付回调异常
*/
public function handle(Exception $exception, $request_data = array()) {
$exception_type = get_class($exception);
switch ($exception_type) {
case 'Validation_Exception':
return $this->handle_validation_exception($exception, $request_data);
case 'Database_Exception':
return $this->handle_database_exception($exception, $request_data);
case 'Payment_Processor_Exception':
return $this->handle_payment_exception($exception, $request_data);
default:
return $this->handle_generic_exception($exception, $request_data);
}
}
/**
* 处理验证异常
*/
private function handle_validation_exception(Validation_Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'支付回调数据验证失败: {message}',
array(
'message' => $exception->getMessage(),
'errors' => $exception->getValidationErrors(),
'request_data' => $request_data
)
);
// 返回标准错误响应
return array(
'status' => 'error',
'code' => 'VALIDATION_FAILED',
'message' => '数据验证失败',
'timestamp' => current_time('mysql')
);
}
/**
* 处理数据库异常
*/
private function handle_database_exception(Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_ERROR,
'支付回调数据库错误: {message}',
array(
'message' => $exception->getMessage(),
'request_data' => $request_data
)
);
// 尝试重试逻辑
if ($this->should_retry($exception)) {
return $this->retry_operation($request_data);
}
// 进入降级模式
return $this->fallback_processing($request_data);
}
/**
* 处理支付处理异常
*/
private function handle_payment_exception(Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_ERROR,
'支付处理异常: {message}',
array(
'message' => $exception->getMessage(),
'request_data' => $request_data
)
);
// 标记订单为需要人工审核
$this->flag_order_for_manual_review(
$request_data['order_id'] ?? 0,
$exception->getMessage()
);
return array(
'status' => 'pending',
'code' => 'MANUAL_REVIEW_REQUIRED',
'message' => '支付需要人工审核',
/**
* 支付回调异常处理器
*/
class Payment_Exception_Handler {
private $logger;
public function __construct() {
$this->logger = new Payment_Security_Logger();
}
/**
* 处理支付回调异常
*/
public function handle(Exception $exception, $request_data = array()) {
$exception_type = get_class($exception);
switch ($exception_type) {
case 'Validation_Exception':
return $this->handle_validation_exception($exception, $request_data);
case 'Database_Exception':
return $this->handle_database_exception($exception, $request_data);
case 'Payment_Processor_Exception':
return $this->handle_payment_exception($exception, $request_data);
default:
return $this->handle_generic_exception($exception, $request_data);
}
}
/**
* 处理验证异常
*/
private function handle_validation_exception(Validation_Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_WARNING,
'支付回调数据验证失败: {message}',
array(
'message' => $exception->getMessage(),
'errors' => $exception->getValidationErrors(),
'request_data' => $request_data
)
);
// 返回标准错误响应
return array(
'status' => 'error',
'code' => 'VALIDATION_FAILED',
'message' => '数据验证失败',
'timestamp' => current_time('mysql')
);
}
/**
* 处理数据库异常
*/
private function handle_database_exception(Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_ERROR,
'支付回调数据库错误: {message}',
array(
'message' => $exception->getMessage(),
'request_data' => $request_data
)
);
// 尝试重试逻辑
if ($this->should_retry($exception)) {
return $this->retry_operation($request_data);
}
// 进入降级模式
return $this->fallback_processing($request_data);
}
/**
* 处理支付处理异常
*/
private function handle_payment_exception(Exception $exception, $request_data) {
$this->logger->log_callback(
Payment_Security_Logger::LOG_LEVEL_ERROR,
'支付处理异常: {message}',
array(
'message' => $exception->getMessage(),
'request_data' => $request_data
)
);
// 标记订单为需要人工审核
$this->flag_order_for_manual_review(
$request_data['order_id'] ?? 0,
$exception->getMessage()
);
return array(
'status' => 'pending',
'code' => 'MANUAL_REVIEW_REQUIRED',
'message' => '支付需要人工审核',


