Repository navigation
Conversation
The SESSION entry said that the collection becomes available only after setsid, which is not what libModSecurity v3 does: it accepts SESSION without setsid and stores the data without a session key, so every transaction that does the same shares it. In an LMDB build the keys don't include the collection name either, so such a variable can overwrite, and be overwritten by, a variable with the same name in another collection that has no key, for example GLOBAL without initcol. Say that SESSION must be initialized with setsid, add a warning with the v3 behavior, and link the setsid entry to it. Refs owasp-modsecurity/ModSecurity#2442
fzipi
left a comment
There was a problem hiding this comment.
Thanks @airween. I checked the v3 claims against v3/master, and they hold:
SetSID::evaluate()is the only place that setsm_session_collection_key, which is empty by default, so SESSION withoutsetsidis read and written under an empty key.- With LMDB, every collection gets its env and DBI from the
MDBEnvProvidersingleton, which opens one unnamed database (mdb_dbi_open(txn, NULL, ...)). The stored key iscompartment::webappid::name, with no collection name, so SESSION and GLOBAL without a key can collide. - With the in-memory backend, SESSION is its own
InMemoryPerProcessobject, as the description says.
One problem: the example under the warning does what the warning says not to do. The warning says to use SESSION "only after setsid has run with a non-empty session token, for example by checking the token in the rule that calls setsid, as in the example below". But checking the token in rule 70 only skips the setsid. Rules 71 and 72 still run without a session. I ran the example on v3/master with a request to /cgi-bin/finger and no cookie:
(Rule: 70) Executing operator "Rx" with param "^$" against REQUEST_COOKIES:PHPSESSID.
(Rule: 71) Executing operator "Rx" with param "^/cgi-bin/finger$" against REQUEST_URI.
Saving variable: SESSION:score with value: 10
So every request without the cookie adds to the same shared score, which is the case the warning describes. Without setsid, SESSIONID is an empty string (I checked: SecRule SESSIONID "@rx ^$" matches), so the example could skip the SESSION rules when there is no session:
SecRule REQUEST_COOKIES:PHPSESSID "!@rx ^$" \
"id:70,phase:2,pass,nolog,setsid:%{REQUEST_COOKIES.PHPSESSID}"
# Skip the SESSION rules if setsid didn't run
SecRule SESSIONID "@rx ^$" \
"id:73,phase:2,pass,nolog,skipAfter:END_SESSION_RULES"
(rules 71, 72 and the deny rule)
SecMarker END_SESSION_RULES
Then the warning could say "for example by skipping the rules that use SESSION when SESSIONID is empty, as in the example below". I only tested this on v3. In v2, SESSION without setsid isn't available at all, so the guard is harmless there.
The warning tells to use SESSION only after setsid, but the example only skipped the setsid call without a session cookie: rules 71-73 still ran, and every request without the cookie added to the same shared score. Add a rule that skips the SESSION rules to a SecMarker if SESSIONID is empty, renumber the rules after it, and say in the warning and in the introduction of the example how the example does it.
|
Thanks @fzipi, you're right: checking the token in rule 70 only skips I added your |
Proposed changes
Document that SESSION has to be initialized with
setsidbefore it is used, as agreed in owasp-modsecurity/ModSecurity#2442.setsid, and a warning describes the v3 behavior:setsid, the data is stored without a session key, so it is shared by every transaction that does the same, whatever session it belongs to;initcol. This is what the issue reported.Closes owasp-modsecurity/ModSecurity#2442
Further comments
The LMDB part is based on the current v3 source: the LMDB backend keeps all collections in one unnamed database (
src/collection/backend/lmdb.cc), the key iscompartment::webappid::namewithout the collection name (headers/modsecurity/collection/collection.h), and onlysetsidsets the SESSION key (src/actions/set_sid.cc). With the default in-memory backend, SESSION is a separate object, so it doesn't collide with other collections, but the data is still shared by all sessions.🤖 Generated with help of Claude Code, Opus 5.5