141 lines
6.3 KiB
PHP
141 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace classes;
|
|
|
|
class security_schema_bootstrap
|
|
{
|
|
private static bool $initialized = false;
|
|
|
|
public static function ensureTables(): void
|
|
{
|
|
if (self::$initialized) {
|
|
return;
|
|
}
|
|
|
|
global $db;
|
|
|
|
$queries = [
|
|
"CREATE TABLE IF NOT EXISTS security_firewall_rules (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
action VARCHAR(16) NOT NULL,
|
|
target_type VARCHAR(32) NOT NULL,
|
|
target_value VARCHAR(255) NOT NULL,
|
|
route_pattern VARCHAR(255) NULL,
|
|
priority INT NOT NULL DEFAULT 100,
|
|
reason TEXT NULL,
|
|
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
|
expires_at DATETIME NULL,
|
|
metadata_json LONGTEXT NULL,
|
|
created_by INT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
deleted_at DATETIME NULL,
|
|
INDEX idx_security_firewall_rules_active (enabled, deleted_at, expires_at),
|
|
INDEX idx_security_firewall_rules_target (target_type, target_value),
|
|
INDEX idx_security_firewall_rules_priority (priority)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
|
|
"CREATE TABLE IF NOT EXISTS security_policy_rules (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
rule_key VARCHAR(64) NOT NULL,
|
|
enabled TINYINT(1) NOT NULL DEFAULT 1,
|
|
threshold_count INT NOT NULL,
|
|
window_seconds INT NOT NULL,
|
|
mode VARCHAR(16) NOT NULL DEFAULT 'observe',
|
|
exempt_permission_nodes_json LONGTEXT NULL,
|
|
updated_by INT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY uq_security_policy_rules_key (rule_key)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
|
|
"CREATE TABLE IF NOT EXISTS security_policy_events (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
rule_key VARCHAR(64) NOT NULL,
|
|
subject_type VARCHAR(32) NOT NULL,
|
|
subject_key VARCHAR(191) NOT NULL,
|
|
route_path VARCHAR(255) NULL,
|
|
route_template VARCHAR(255) NULL,
|
|
method VARCHAR(16) NULL,
|
|
source_ip VARCHAR(64) NULL,
|
|
customer_number INT NULL,
|
|
user_id INT NULL,
|
|
subuser_id INT NULL,
|
|
metadata_json LONGTEXT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_security_policy_events_window (rule_key, subject_type, subject_key, created_at),
|
|
INDEX idx_security_policy_events_created (created_at),
|
|
INDEX idx_security_policy_events_customer (customer_number, created_at),
|
|
INDEX idx_security_policy_events_ip (source_ip, created_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
|
|
"CREATE TABLE IF NOT EXISTS security_incidents (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
incident_key VARCHAR(191) NOT NULL,
|
|
type VARCHAR(64) NOT NULL,
|
|
severity VARCHAR(16) NOT NULL DEFAULT 'medium',
|
|
status VARCHAR(32) NOT NULL DEFAULT 'open',
|
|
title VARCHAR(255) NOT NULL,
|
|
source_ip VARCHAR(64) NULL,
|
|
customer_number INT NULL,
|
|
user_id INT NULL,
|
|
subuser_id INT NULL,
|
|
route_path VARCHAR(255) NULL,
|
|
route_template VARCHAR(255) NULL,
|
|
method VARCHAR(16) NULL,
|
|
related_rule_id BIGINT UNSIGNED NULL,
|
|
related_firewall_rule_id BIGINT UNSIGNED NULL,
|
|
occurrence_count INT NOT NULL DEFAULT 1,
|
|
metadata_json LONGTEXT NULL,
|
|
first_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
last_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
resolved_by INT NULL,
|
|
resolved_at DATETIME NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
UNIQUE KEY uq_security_incidents_key (incident_key),
|
|
INDEX idx_security_incidents_status_seen (status, last_seen_at),
|
|
INDEX idx_security_incidents_type_seen (type, last_seen_at),
|
|
INDEX idx_security_incidents_customer_seen (customer_number, last_seen_at),
|
|
INDEX idx_security_incidents_ip_seen (source_ip, last_seen_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
|
|
"CREATE TABLE IF NOT EXISTS security_incident_notes (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
incident_id BIGINT UNSIGNED NOT NULL,
|
|
note TEXT NOT NULL,
|
|
created_by INT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_security_incident_notes_incident (incident_id, created_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
|
|
];
|
|
|
|
foreach ($queries as $query) {
|
|
$db->query($query);
|
|
}
|
|
|
|
self::$initialized = true;
|
|
}
|
|
|
|
public static function tablesExist(): bool
|
|
{
|
|
global $db;
|
|
|
|
$database = $db->escape_string($db->getDatabase());
|
|
$result = $db->query(
|
|
"SELECT COUNT(*) AS count
|
|
FROM information_schema.tables
|
|
WHERE table_schema = '{$database}'
|
|
AND table_name IN (
|
|
'security_firewall_rules',
|
|
'security_policy_rules',
|
|
'security_policy_events',
|
|
'security_incidents',
|
|
'security_incident_notes'
|
|
)"
|
|
);
|
|
$row = $result ? $result->fetch_assoc() : ['count' => 0];
|
|
return (int)($row['count'] ?? 0) === 5;
|
|
}
|
|
}
|