-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Allow regular expressions in ctl:ruleRemoveTargetByX variable names II. #3121
base: v2/master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strlen(value) could be cached in a variable, as it's used several times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if(strlen(value) > 2 && value[0] == '/' && ...
Better to begin with check of value[0] as, most of the time, the test will be false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (regex == NULL) { ...
We should return 0 immediately to simplify the flow.
Let's do it for if (targets != NULL)
also when we're at it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if((strlen(myvalue) == strlen(value)) && strncasecmp(myvalue,value,strlen(myvalue)) == 0)
Why not
if(strcasecmp(myvalue,value,strlen(myvalue)) == 0)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else if (value == NULL && myvalue == NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
}
match = 1;
} else if (value == NULL && myvalue != NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
}
match = 1;
}
Simplify:
else {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target);
}
match = 1;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside if(strncasecmp(myname, name,strlen(myname)) == 0)
there's a test if(value != NULL && myvalue != NULL)
If value is not NULL, like TX:a, REQUEST_HEADERS:abc, 'myvalue' (corresponding to the actual target) cannot be NULL (TX alone is not possible).
Thus if(value != NULL)
is sufficient
Quality Gate failedFailed conditions See analysis details on SonarCloud Catch issues before they fail your Quality Gate with our IDE extension SonarLint |
Thanks, fixed in c796804. |
I introduced the |
I think we can change it in a next round. |
|
Thanks, this make sense - see 1790659. |
After a quick analysis I'm not sure about that. Even though it might |
Using both checks prevents the segfault. If the user's config is wrong, then it can lead to
which makes no sense, but if the user confuses a collection with a variable, then it could be a problem. I suggest to keep that there. |
The following code is strictly equivalent to the existing one, except that it removes one 'if' level (return early) and simplify a bit this code that becomes complex to follow:
|
I see your point, yes, that would make the code more cleaner. |
if(value_len > 2 && value[0] == '/' && value[value_len - 1] == '/') { | ||
value[value_len - 1] = '\0'; | ||
#ifdef WITH_PCRE2 | ||
regex = msc_pregcomp(msr->mp, value + 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (copied) code contains a memory leak: the regex
variable compiled in each cycle during the exclusion check, but never freed (never called msc_pcre_cleanup()).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should reorganize this part. I would expect that regex
variable above must be compiled during startup, and not when the engine inspect the exclusion.
I'm wondering why is a cycle here, I mean This would be make sense if the syntax of rule were allowed multiple targets, eg:
but this is not allowed. Variable @marcstern, @dune73 do you have any idea, what was the original aim of this solution? |
Where is it defined that multiple targets is not allowed? |
How looks like the syntax? |
|
The parser does not allow this syntax. I tried this and other similar syntax's with no luck. The error message is:
The |
My syntax was indeed incorrect. |
@airween asked me to chime in. Sorry to be so silent otherwise. I see how the definition of multiple targets on a single runtime rule exclusion within single quotes would work syntactically. But I do not think it brings much of an advantage beyond an assumed minimal speed improvement. The rule exclusion becomes harder to read and if you think of a graphical rule editor the UX designer would probably curse you using very harsh words for this addition. Or in other words: Adding a regex to the target definition: Solves an itch where we have no alternative. Adding the option to add multiple arguments to a single ctl statement: Solves a small problem at the cost of hard to maintain config. |
Sorry, but I don't see any differences. |
do you think this syntax works? I wasn't able to write any rule with multiple targets.
I'm not sure this brings any speed improvements. In both cases there are the same cycles.
This is a valuable argument on long time, but may be we don't need to care of this issue actually.
Actually regex in targets (with this implementation) would be very-very slow. If there is a real user demand (and based on the comments under original PR there is) I agree we need to implement this feature, but not this way. The questions are:
|
Honestly, I think the speed problem is around the whole concept of runtime rule exclusions and how it is implemented. You have a target list and then you remove individual targets from that list based on the ignore-list at runtime. The way it is done is very slow, very often slower than executing the rule itself. That effectively means that disabling rules via rule exclusions for speed gain is not possible. (And that use case is very real: If I assure that an ARGS follows a positive definition, I would like to improve the performance by removing this ARGS from further evaluation, but this approach actually degrades performance for simple ARGS. It's faster to run the rules ...) And I remember looking at the execution in detail and I think either ModSec v2 or v3 would actually run the rule and remove the result if there was a rule exclusion instead of skipping the execution. But I am no longer 100% sure this was really the case. But back to this problem here: The situation that pops up regularly is random cookie names and also random or enumerated argument names, thus targets where you do not know the name in advance. For the cookies, there is no alternative to disabling cookie inspection for a rule completely because the (Drupal!) session cookie has a random name. I think the regex definition of runtime rule exclusions is needed, but the speed should be improved. |
yes.
First I want to understand why the exclusions handling code wants to handle multiple targets, but the parser does not allow it. So it would be very good to see a valid syntax, there the exclusion has multiple targets and parser eats it. |
ctl:'ruleRemoveTargetById=942100;ARGS:/^password[\d+]$/,ARGS:abc'" |
I think having a multiple targets is probably (a little bit) quicker than specifying multiple ctl actions. The main problem is that a lot of parsing is done at run-time and especially the regex compiling. Nota that, for one of the most common cases, excluding a target from all rules (like the Drupal session cookie), there's a much better solution: allowing all collections to be writeable. That way, we can remove it completely. But that's another story (that will come back, I promise). |
|
I agree with @marcstern completely. And you probably need to give your parser some rest @airween. It's clearly having a bad day. |
This is what I want to solve, but I don't see how multiple targets handling works. I mean I see the code, but I can't write a rule which will be allowed by the config parser. |
You're right @airween, the syntax doesn't work ... because of a bug I fixed in my test version. If you don't use a , it should work: |
oh, it's good to know.
So before we continue the work, we should merge this PR?
I tried without regex format, but it still don't work:
the result:
The config:
|
|
Hey, everybody. I have some news. I came across the need to use regular expressions in ctl:ruleRemoveById Example: SecRule REQUEST_METHOD "@Streq POST" My task, to exclude checking not the whole request, but only a part of the request body, which is json. I.e. to disable checking of those json keys that match my regular expression. Error:
|
regex = msc_pregcomp(msr->mp, value + 1, | ||
PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY, (const char **)&errptr, &erroffset); | ||
#endif | ||
if (regex == NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If needed, logging should be added in msc_pregcomp(), so it's available for all calls
} | ||
} else { | ||
#ifdef WITH_PCRE2 | ||
if (!(msc_regexec(regex, myvalue, strlen(myvalue), &errptr) == PCRE2_ERROR_NOMATCH)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct check is if (msc_regexec(...) < 0)
Same for PCRE2
This PR is the renewal and addition of the PR #1683, and solves #911.
Example:
The new patch works with PCRE2 too.
Actually it is only for v2, so until there is no patch for v3 I don't want to merge it (hope I can do that soon).
Many thanks for your work, @vvidic, the credit is yours.