diff --git a/www/nginx/src/opnsense/mvc/app/controllers/OPNsense/Nginx/forms/naxsi_rule.xml b/www/nginx/src/opnsense/mvc/app/controllers/OPNsense/Nginx/forms/naxsi_rule.xml index 6a8232fc0..87b7bd867 100644 --- a/www/nginx/src/opnsense/mvc/app/controllers/OPNsense/Nginx/forms/naxsi_rule.xml +++ b/www/nginx/src/opnsense/mvc/app/controllers/OPNsense/Nginx/forms/naxsi_rule.xml @@ -19,19 +19,23 @@ naxsi_rule.identifier - text - The unique numerical ID of the rule, that will be used in logs and in whitelists. IDs inferior to 1000 are reserved for Naxsi internal rules (protocol mismatch etc.) + select_multiple + true + + select_multiple + For blacklist rules, the unique numerical ID of the rule, that will be used in logs and in whitelists. IDs inferior to 1000 are reserved for Naxsi internal rules (protocol mismatch etc.)<br>For whitelists, specify one or more comma separated IDs to whitelist. 0 whitelists all rules. naxsi_rule.ruletype dropdown + Main rules increase the policiy's score if matched. Basic rules are added directly to the location and match immeditaly. Basic rules are specifically useful for whitelist rules. Also basic rules need to be added to a policy to allow association with a location. naxsi_rule.regex checkbox - If enabled, the match value, the URL, named parameters and headers are matched using regular expressions; otherwise only exact matches trigger the rule. + If enabled, the match value, the URL, named parameters and headers are matched using regular expressions; otherwise only exact matches trigger the rule. naxsi_rule.match_value @@ -43,12 +47,13 @@ dropdown + A blacklist rule increases the policy's score if the pattern matches. A whitelist rule instructs Naxsi to ignore specific rules under specific conditions. naxsi_rule.args checkbox - Search for matchs in a request's GET arguments. + Search for matchs in a request's GET arguments. naxsi_rule.url @@ -60,7 +65,7 @@ naxsi_rule.headers checkbox - Search for matchs in a request's HTTP headers. + Search for matchs in a request's HTTP headers. naxsi_rule.body diff --git a/www/nginx/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/NaxsiIdentifierConstraint.php b/www/nginx/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/NaxsiIdentifierConstraint.php new file mode 100644 index 000000000..085b5d9f7 --- /dev/null +++ b/www/nginx/src/opnsense/mvc/app/models/OPNsense/Base/Constraints/NaxsiIdentifierConstraint.php @@ -0,0 +1,98 @@ +getOption('node'); + if ($node) { + $parentNode = $node->getParentNode(); + + // Validate whitelist IDs + if ($parentNode->match_type == 'wl') { + $vals = explode(",", (string)$node); // Whitelists can use several IDs + $pos = 0; + $neg = 0; + + // Check each ID + foreach ($vals as $val) { + $intval = intval($val); + + if (!is_numeric($val)) { + $validator->appendMessage(new Message(gettext("All rule IDs need to be numeric."), $attribute)); + } + // 0 can only be used solely + elseif ($intval == 0 && count($vals) > 1) { + $validator->appendMessage(new Message(gettext("If ID 0 is specified, no other IDs can be listed."), $attribute)); + } + elseif ($intval < 0) { + $neg++; + } + elseif ($intval > 0) { + $pos++; + } + } + + // All IDs need to be positive or all negative + if ($neg > 0 && $pos > 0) { + $validator->appendMessage(new Message(gettext("Negative and positive IDs cannot be mixed."), $attribute)); + } + } + // Validate rule IDs + else { + $val = (string)$node; + if (!is_numeric($val)) { + // Did the user try to specify multiple IDs? + if (strpos($val, ',')) { + $validator->appendMessage(new Message(gettext("Rules can only have a single ID."), $attribute)); + } + else { + $validator->appendMessage(new Message(gettext("Rule IDs need to be numeric."), $attribute)); + } + } + // Check that no internal ID was used + elseif (intval($val) < 1000) { + $validator->appendMessage(new Message(gettext("Rule IDs lower than 1000 are reserved for internal rules."), $attribute)); + } + } + } + + return true; + } +} diff --git a/www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml b/www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml index ab5384053..d079f90b7 100644 --- a/www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml +++ b/www/nginx/src/opnsense/mvc/app/models/OPNsense/Nginx/Nginx.xml @@ -1,6 +1,6 @@ //OPNsense/Nginx - 1.20.0 + 1.20.1 nginx web server, reverse proxy and waf @@ -530,9 +530,13 @@ - + Y - 1000 + + + NaxsiIdentifierConstraint + + N @@ -557,6 +561,11 @@ Blacklist Whitelist + + + identifier.check001 + + Y diff --git a/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/naxsirule.conf b/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/naxsirule.conf index a3410bc3d..c6e45870b 100644 --- a/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/naxsirule.conf +++ b/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/naxsirule.conf @@ -45,13 +45,13 @@ {{ mz_matches|join('|') }} {%- endmacro %} {% macro naxsi_rule(uuid, rule, ruletype) -%} -{% if rule.message is defined and rule.match_value is defined %} +{% if rule.match_type == 'id' %} {{ ruletype }}{% if rule.negate is defined and rule.negate == '1' %} negative{% endif - %} {{ rule.match_type }}:{{ rule.identifier }} "{% if rule.regex == '1' %}rx{% else %}str{% endif + %} id:{{ rule.identifier }} "{% if rule.regex == '1' %}rx{% else %}str{% endif %}:{{ rule.match_value }}" "msg:{{ rule.message }}" "mz:{{ naxsi_mzhelper(rule) }}" "s:$policy{{ uuid.replace('-', '') }}:{{ rule.score }}"; -{% else %} - {{ ruletype }} {{ rule.match_type }}:{{ rule.identifier }}; +{% elif rule.match_type == 'wl' %} + {{ ruletype }} wl:{{ rule.identifier }}{% if naxsi_mzhelper(rule) != '' %} "mz:{{ naxsi_mzhelper(rule) }}"{% endif %}; {% endif %} {%- endmacro %} {% if naxsi_ruletype == 'basic' %}