/** * V20.0.700.1 - Enhanced Security Classes * NIST Cybersecurity Framework Aligned */ class BVS_Security_Enhanced { /** * Validate URL with SSRF protection * Prevents Server-Side Request Forgery attacks */ public static function validate_url_safe($url) { $url = esc_url_raw(trim($url)); if (!filter_var($url, FILTER_VALIDATE_URL)) { return ['valid' => false, 'error' => 'Invalid URL format']; } $parsed = parse_url($url); if (!in_array($parsed['scheme'] ?? '', ['http', 'https'])) { return ['valid' => false, 'error' => 'Only HTTP/HTTPS protocols allowed']; } if (!isset($parsed['host']) || empty($parsed['host'])) { return ['valid' => false, 'error' => 'Invalid hostname']; } // SSRF PROTECTION $ip = gethostbyname($parsed['host']); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { error_log('BVS Security: SSRF attempt blocked - Private IP: ' . $ip); return ['valid' => false, 'error' => 'Internal/private URLs not allowed']; } $localhost_patterns = ['localhost', '127.0.0.1', '0.0.0.0', '::1']; if (in_array(strtolower($parsed['host']), $localhost_patterns)) { return ['valid' => false, 'error' => 'Localhost URLs not allowed']; } $suspicious_tlds = ['tk', 'ml', 'ga', 'cf', 'gq', 'buzz', 'link']; $tld = strtolower(substr(strrchr($parsed['host'], "."), 1)); $fraud_modifier = in_array($tld, $suspicious_tlds) ? 10 : 0; return [ 'valid' => true, 'url' => $url, 'fraud_score_modifier' => $fraud_modifier, 'warning' => $fraud_modifier > 0 ? 'Suspicious TLD detected: .' . $tld : null ]; } /** * Check URL reputation using Google Safe Browsing */ public static function check_url_reputation($url) { $api_key = get_option('bvs_google_safebrowsing_api_key', ''); if (empty($api_key)) { return ['checked' => false, 'safe' => 'unknown']; } $endpoint = 'https://safebrowsing.googleapis.com/v4/threatMatches:find'; $request_body = [ 'client' => [ 'clientId' => 'bvs-validator', 'clientVersion' => BVS_VERSION ], 'threatInfo' => [ 'threatTypes' => ['MALWARE', 'SOCIAL_ENGINEERING', 'UNWANTED_SOFTWARE'], 'platformTypes' => ['ANY_PLATFORM'], 'threatEntryTypes' => ['URL'], 'threatEntries' => [['url' => $url]] ] ]; $response = wp_remote_post($endpoint . '?key=' . $api_key, [ 'timeout' => 10, 'headers' => ['Content-Type' => 'application/json'], 'body' => wp_json_encode($request_body), 'sslverify' => true ]); if (is_wp_error($response)) { return ['checked' => false, 'safe' => 'unknown']; } $body = json_decode(wp_remote_retrieve_body($response), true); if (!empty($body['matches'])) { return [ 'checked' => true, 'safe' => false, 'threat_types' => array_unique(array_column($body['matches'], 'threatType')), 'action' => 'REJECT', 'fraud_score' => 100, 'reason' => 'URL flagged as malicious' ]; } return ['checked' => true, 'safe' => true]; } } class BVS_Rate_Limiter { public static function check($identifier, $limit = 10, $period = 3600) { $transient_key = 'bvs_rate_' . md5($identifier); $attempts = get_transient($transient_key); if ($attempts === false) { set_transient($transient_key, 1, $period); return ['allowed' => true, 'remaining' => $limit - 1]; } if ($attempts >= $limit) { return ['allowed' => false, 'remaining' => 0, 'message' => 'Rate limit exceeded']; } set_transient($transient_key, $attempts + 1, $period); return ['allowed' => true, 'remaining' => $limit - $attempts - 1]; } } class BVS_Security_Logger { public static function create_log_table() { global $wpdb; $table_name = $wpdb->prefix . 'bvs_security_logs'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id bigint UNSIGNED NOT NULL AUTO_INCREMENT, event_type varchar(50) NOT NULL, severity enum('INFO','WARNING','CRITICAL') DEFAULT 'INFO', details longtext, url varchar(500), ip_address varchar(45), user_agent text, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY event_type (event_type), KEY severity (severity), KEY created_at (created_at) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } public static function log($event_type, $details = [], $severity = 'INFO') { global $wpdb; $table_name = $wpdb->prefix . 'bvs_security_logs'; $wpdb->insert($table_name, [ 'event_type' => sanitize_text_field($event_type), 'severity' => $severity, 'details' => wp_json_encode($details), 'url' => $_SERVER['REQUEST_URI'] ?? '', 'ip_address' => self::get_client_ip(), 'user_agent' => substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 500), 'created_at' => current_time('mysql') ]); if ($severity === 'CRITICAL') { self::send_alert($event_type, $details); } } private static function get_client_ip() { $keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR']; foreach ($keys as $key) { if (!empty($_SERVER[$key])) { $ip = $_SERVER[$key]; if (strpos($ip, ',') !== false) { $ip = trim(explode(',', $ip)[0]); } return sanitize_text_field($ip); } } return 'unknown'; } private static function send_alert($event_type, $details) { $admin_email = get_option('admin_email'); $subject = '[BVS] Security Alert: ' . $event_type; $message = "Event: {$event_type}\n"; $message .= "Time: " . current_time('mysql') . "\n"; $message .= "Details: " . print_r($details, true); wp_mail($admin_email, $subject, $message); } } /** * V20.0.700.1 - Core Web Vitals Analyzer */ class BVS_Core_Web_Vitals { public static function analyze($url) { $api_key = get_option('bvs_pagespeed_api_key', ''); if (empty($api_key)) { return ['error' => 'PageSpeed API key not configured']; } $endpoint = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed'; $response = wp_remote_get(add_query_arg([ 'url' => $url, 'key' => $api_key, 'strategy' => 'mobile', 'category' => 'performance' ], $endpoint), ['timeout' => 60, 'sslverify' => true]); if (is_wp_error($response)) { return ['error' => $response->get_error_message()]; } $data = json_decode(wp_remote_retrieve_body($response), true); if (empty($data['lighthouseResult'])) { return ['error' => 'Invalid API response']; } $audits = $data['lighthouseResult']['audits']; $metrics = [ 'performance_score' => round($data['lighthouseResult']['categories']['performance']['score'] * 100), 'lcp' => $audits['largest-contentful-paint']['numericValue'] ?? 0, 'lcp_rating' => self::rate_lcp($audits['largest-contentful-paint']['numericValue'] ?? 0), 'fid' => $audits['max-potential-fid']['numericValue'] ?? 0, 'fid_rating' => self::rate_fid($audits['max-potential-fid']['numericValue'] ?? 0), 'cls' => $audits['cumulative-layout-shift']['numericValue'] ?? 0, 'cls_rating' => self::rate_cls($audits['cumulative-layout-shift']['numericValue'] ?? 0), 'ttfb' => $audits['server-response-time']['numericValue'] ?? 0, ]; $metrics['cwv_score'] = self::calculate_score($metrics); $metrics['cwv_rating'] = $metrics['cwv_score'] >= 75 ? 'Good' : ($metrics['cwv_score'] >= 50 ? 'Needs Improvement' : 'Poor'); $metrics['recommendations'] = self::generate_recommendations($metrics, $audits); return $metrics; } private static function rate_lcp($ms) { return $ms <= 2500 ? 'Good' : ($ms <= 4000 ? 'Needs Improvement' : 'Poor'); } private static function rate_fid($ms) { return $ms <= 100 ? 'Good' : ($ms <= 300 ? 'Needs Improvement' : 'Poor'); } private static function rate_cls($value) { return $value <= 0.1 ? 'Good' : ($value <= 0.25 ? 'Needs Improvement' : 'Poor'); } private static function calculate_score($metrics) { $score = 0; if ($metrics['lcp_rating'] === 'Good') $score += 25; elseif ($metrics['lcp_rating'] === 'Needs Improvement') $score += 15; if ($metrics['fid_rating'] === 'Good') $score += 25; elseif ($metrics['fid_rating'] === 'Needs Improvement') $score += 15; if ($metrics['cls_rating'] === 'Good') $score += 25; elseif ($metrics['cls_rating'] === 'Needs Improvement') $score += 15; $score += round($metrics['performance_score'] / 4); return $score; } private static function generate_recommendations($metrics, $audits) { $recs = []; if ($metrics['lcp_rating'] !== 'Good') { $recs[] = 'Improve LCP (' . round($metrics['lcp']) . 'ms): Optimize images, use CDN, improve server response'; } if ($metrics['fid_rating'] !== 'Good') { $recs[] = 'Reduce FID (' . round($metrics['fid']) . 'ms): Minimize JavaScript, optimize third-party scripts'; } if ($metrics['cls_rating'] !== 'Good') { $recs[] = 'Fix CLS (' . round($metrics['cls'], 3) . '): Add size attributes to images, avoid layout shifts'; } return $recs; } } /** * V20.0.700.1 - Structured Data Analyzer */ class BVS_Structured_Data_Analyzer { public static function analyze($html, $url) { $structured = [ 'json_ld_count' => 0, 'json_ld_types' => [], 'open_graph' => [], 'twitter_card' => [], 'schema_score' => 0, 'recommendations' => [] ]; // JSON-LD if (preg_match_all('/