Fix WAF whitelist ordering and URI matching
This commit is contained in:
@@ -257,6 +257,7 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
{
|
{
|
||||||
$ruleId = (string) ($entry['rule_id'] ?? '');
|
$ruleId = (string) ($entry['rule_id'] ?? '');
|
||||||
$uri = (string) ($entry['uri'] ?? '');
|
$uri = (string) ($entry['uri'] ?? '');
|
||||||
|
$uriPath = $this->stripQueryString($uri);
|
||||||
$host = (string) ($entry['host'] ?? '');
|
$host = (string) ($entry['host'] ?? '');
|
||||||
$ip = (string) ($entry['remote_ip'] ?? '');
|
$ip = (string) ($entry['remote_ip'] ?? '');
|
||||||
|
|
||||||
@@ -281,10 +282,10 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
if ($matchType === 'ip' && $matchValue !== '' && $this->ipMatches($ip, $matchValue)) {
|
if ($matchType === 'ip' && $matchValue !== '' && $this->ipMatches($ip, $matchValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'uri_exact' && $matchValue !== '' && $uri === $matchValue) {
|
if ($matchType === 'uri_exact' && $matchValue !== '' && ($uri === $matchValue || $uriPath === $matchValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'uri_prefix' && $matchValue !== '' && str_starts_with($uri, $matchValue)) {
|
if ($matchType === 'uri_prefix' && $matchValue !== '' && (str_starts_with($uri, $matchValue) || str_starts_with($uriPath, $matchValue))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'host' && $matchValue !== '' && $host === $matchValue) {
|
if ($matchType === 'host' && $matchValue !== '' && $host === $matchValue) {
|
||||||
@@ -306,6 +307,7 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
|
|
||||||
$ruleId = (string) ($entry['rule_id'] ?? '');
|
$ruleId = (string) ($entry['rule_id'] ?? '');
|
||||||
$uri = (string) ($entry['uri'] ?? '');
|
$uri = (string) ($entry['uri'] ?? '');
|
||||||
|
$uriPath = $this->stripQueryString($uri);
|
||||||
$host = (string) ($entry['host'] ?? '');
|
$host = (string) ($entry['host'] ?? '');
|
||||||
$ip = (string) ($entry['remote_ip'] ?? '');
|
$ip = (string) ($entry['remote_ip'] ?? '');
|
||||||
|
|
||||||
@@ -322,10 +324,10 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
if ($matchType === 'ip' && $matchValue !== '' && $this->ipMatches($ip, $matchValue)) {
|
if ($matchType === 'ip' && $matchValue !== '' && $this->ipMatches($ip, $matchValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'uri_exact' && $matchValue !== '' && $uri === $matchValue) {
|
if ($matchType === 'uri_exact' && $matchValue !== '' && ($uri === $matchValue || $uriPath === $matchValue)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'uri_prefix' && $matchValue !== '' && str_starts_with($uri, $matchValue)) {
|
if ($matchType === 'uri_prefix' && $matchValue !== '' && (str_starts_with($uri, $matchValue) || str_starts_with($uriPath, $matchValue))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ($matchType === 'host' && $matchValue !== '' && $host === $matchValue) {
|
if ($matchType === 'host' && $matchValue !== '' && $host === $matchValue) {
|
||||||
@@ -365,8 +367,9 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
public function whitelistEntry(array $record): void
|
public function whitelistEntry(array $record): void
|
||||||
{
|
{
|
||||||
$rules = $this->getWhitelistRules();
|
$rules = $this->getWhitelistRules();
|
||||||
$matchType = 'uri_exact';
|
$matchType = 'uri_prefix';
|
||||||
$matchValue = (string) ($record['uri'] ?? '');
|
$rawUri = (string) ($record['uri'] ?? '');
|
||||||
|
$matchValue = $this->stripQueryString($rawUri);
|
||||||
if ($matchValue === '') {
|
if ($matchValue === '') {
|
||||||
$matchType = 'ip';
|
$matchType = 'ip';
|
||||||
$matchValue = (string) ($record['remote_ip'] ?? '');
|
$matchValue = (string) ($record['remote_ip'] ?? '');
|
||||||
@@ -417,6 +420,16 @@ class Waf extends Page implements HasForms, HasTable
|
|||||||
->send();
|
->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function stripQueryString(string $uri): string
|
||||||
|
{
|
||||||
|
$pos = strpos($uri, '?');
|
||||||
|
if ($pos === false) {
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
return substr($uri, 0, $pos);
|
||||||
|
}
|
||||||
|
|
||||||
public function removeWhitelistEntry(array $record): void
|
public function removeWhitelistEntry(array $record): void
|
||||||
{
|
{
|
||||||
$rules = $this->getWhitelistRules();
|
$rules = $this->getWhitelistRules();
|
||||||
|
|||||||
@@ -799,7 +799,11 @@ function wafAuditLogList(array $params): array
|
|||||||
$entry['severity'] = $matches[1];
|
$entry['severity'] = $matches[1];
|
||||||
}
|
}
|
||||||
if (preg_match('/\\[uri "([^"]+)"\\]/', $line, $matches)) {
|
if (preg_match('/\\[uri "([^"]+)"\\]/', $line, $matches)) {
|
||||||
$entry['uri'] = $matches[1];
|
$loggedUri = $matches[1];
|
||||||
|
$currentUri = (string) ($entry['uri'] ?? '');
|
||||||
|
if ($currentUri === '' || (!str_contains($currentUri, '?') && $loggedUri !== '')) {
|
||||||
|
$entry['uri'] = $loggedUri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (preg_match('/\\[hostname "([^"]+)"\\]/', $line, $matches)) {
|
if (preg_match('/\\[hostname "([^"]+)"\\]/', $line, $matches)) {
|
||||||
$entry['host'] = $matches[1];
|
$entry['host'] = $matches[1];
|
||||||
@@ -3094,6 +3098,50 @@ function findWafBaseConfig(): ?string
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findWafCoreConfig(): ?string
|
||||||
|
{
|
||||||
|
$paths = [
|
||||||
|
'/etc/modsecurity/modsecurity.conf',
|
||||||
|
'/etc/modsecurity/modsecurity.conf-recommended',
|
||||||
|
'/etc/nginx/modsecurity.conf',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path) && isWafBaseConfigUsable($path)) {
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildWafCrsIncludeLines(): array
|
||||||
|
{
|
||||||
|
$lines = [];
|
||||||
|
|
||||||
|
if (file_exists('/etc/modsecurity/crs/crs-setup.conf')) {
|
||||||
|
$lines[] = 'Include /etc/modsecurity/crs/crs-setup.conf';
|
||||||
|
} elseif (file_exists('/usr/share/modsecurity-crs/crs-setup.conf')) {
|
||||||
|
$lines[] = 'Include /usr/share/modsecurity-crs/crs-setup.conf';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists('/etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf')) {
|
||||||
|
$lines[] = 'Include /etc/modsecurity/crs/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dir('/etc/modsecurity/crs/rules')) {
|
||||||
|
$lines[] = 'Include /etc/modsecurity/crs/rules/*.conf';
|
||||||
|
} elseif (is_dir('/usr/share/modsecurity-crs/rules')) {
|
||||||
|
$lines[] = 'Include /usr/share/modsecurity-crs/rules/*.conf';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists('/etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf')) {
|
||||||
|
$lines[] = 'Include /etc/modsecurity/crs/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lines;
|
||||||
|
}
|
||||||
|
|
||||||
function isModSecurityModuleAvailable(): bool
|
function isModSecurityModuleAvailable(): bool
|
||||||
{
|
{
|
||||||
$output = [];
|
$output = [];
|
||||||
@@ -3186,15 +3234,15 @@ function wafApplySettings(array $params): array
|
|||||||
}
|
}
|
||||||
|
|
||||||
ensureWafUnicodeMapFile();
|
ensureWafUnicodeMapFile();
|
||||||
$baseConfig = findWafBaseConfig();
|
$coreConfig = findWafCoreConfig();
|
||||||
if (!$baseConfig) {
|
if (!$coreConfig) {
|
||||||
file_put_contents(JABALI_WAF_INCLUDE, "# Managed by Jabali\nmodsecurity off;\n");
|
file_put_contents(JABALI_WAF_INCLUDE, "# Managed by Jabali\nmodsecurity off;\n");
|
||||||
return ['success' => false, 'error' => 'ModSecurity base configuration not found'];
|
return ['success' => false, 'error' => 'ModSecurity base configuration not found'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'# Managed by Jabali',
|
'# Managed by Jabali',
|
||||||
'Include "' . $baseConfig . '"',
|
'Include "' . $coreConfig . '"',
|
||||||
'SecRuleEngine On',
|
'SecRuleEngine On',
|
||||||
'SecAuditEngine ' . ($auditLog ? 'On' : 'Off'),
|
'SecAuditEngine ' . ($auditLog ? 'On' : 'Off'),
|
||||||
'SecAuditLog /var/log/nginx/modsec_audit.log',
|
'SecAuditLog /var/log/nginx/modsec_audit.log',
|
||||||
@@ -3207,6 +3255,11 @@ function wafApplySettings(array $params): array
|
|||||||
$rules = array_merge($rules, $whitelistLines);
|
$rules = array_merge($rules, $whitelistLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$crsIncludes = buildWafCrsIncludeLines();
|
||||||
|
if (!empty($crsIncludes)) {
|
||||||
|
$rules = array_merge($rules, $crsIncludes);
|
||||||
|
}
|
||||||
|
|
||||||
file_put_contents(JABALI_WAF_RULES, implode("\n", $rules) . "\n");
|
file_put_contents(JABALI_WAF_RULES, implode("\n", $rules) . "\n");
|
||||||
|
|
||||||
$include = [
|
$include = [
|
||||||
|
|||||||
Reference in New Issue
Block a user