Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (6)
Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughChangesThe module adds the Response body inspection control
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Feature · Severity of issue fixed: Low Sequence Diagram(s)sequenceDiagram
participant Client
participant Nginx
participant ModSecurity
participant AuditLog
Client->>Nginx: request configured location
Nginx->>Nginx: apply modsecurity_response_body
Nginx->>ModSecurity: inspect response body when enabled
ModSecurity->>AuditLog: record response-body and phase-4 matches
Nginx-->>Client: return response body
Merge Risk: ⚪ Minimal · up to The new directive behaves as documented for enabled, disabled, and inherited configurations, with no identified merge-blocking risk. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Full details: Linked Issues checkExplanation The directive provides a runtime control and defaults to enabled. The enabled path preserves response-body inspection. The disabled path avoids forced in-memory buffering and body copies, and the tests cover inheritance and body integrity. However, issue Resolution Update disabled-mode handling so it bypasses the module's post- Full details: Docstring CoverageExplanation Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 4 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
When set to off the header filter no longer forces filter_need_in_memory (so with sendfile enabled file buffers are no longer read into memory before being sent) and the body filter no longer copies response buffers into libmodsecurity. The RESPONSE_BODY phase still runs on the last buffer so phase 4 rules that do not need the body keep working. libmodsecurity copies response bodies of the configured MIME types even with SecResponseBodyAccess Off, and the connector cannot query that setting, so an explicit directive is the only way to avoid the cost.
6e7e8a6 to
2256e6e
Compare
|
|
Hi @tomsommer, thanks for this too. So it's similar to #391 but for the response body, right? And this bypasses the engine's Thank you for this, I have same opinion here like in case of the other PR. I ask for your patience here too. |
|
Hi @airween, thanks for looking at this one too. Yes, it is the response-side counterpart of #391, but I would not describe it as bypassing
With the directive at its default The reason a connector-side switch is needed even when an admin has already set
That second point is what #206 has been asking for since 2020, and it is the part that is not reachable from the rules language at all. It also makes this PR slightly more than a mirror image of #391: the request side is only about not reading and buffering the body, the response side additionally stops forcing the body into memory. On naming, the same offer as in #391 applies: if No rush from my side, and it makes sense to land the earlier PRs first. Happy to rebase whenever that happens. |



what
modsecurity_response_body on | off(http, server, location; defaulton, inherited per location).off:r->filter_need_in_memory, so nginx no longer reads file-backed response buffers (static files, proxied responses buffered to disk) into memory and copies them through the output chain before sending them (withsendfileenabled they are transmitted straight from the file, as they would be without the module);msc_append_response_body()or the per-buffer intervention check;SecResponseBodyAccess/SecResponseBodyMimeTypelogic still decides whether phase 4 rules run;RESPONSE_BODYis empty andRESPONSE_CONTENT_LENGTHis 0.tests/modsecurity-response-body-directive.t(13 assertions): audit-log evidence that aRESPONSE_BODYrule matches by default and not withoffwhile a status-based phase 4 rule still runs, the body is delivered intact, inheritance into a nested location works, and, on--with-debugbuilds, the copy filter's "write new buf t:1 f:1" record appears only for the default location.why
modsecurityis on, regardless ofSecResponseBodyAccess. The FIXME next to that line has said so since 2017.appendResponseBody()only filters on the MIME-type list, not onSecResponseBodyAccess(that is checked inprocessResponseBody()), so turning body access off in the rules does not avoid the copy, and the connector cannot query that setting through the C API. An nginx-level directive is the only lever.references
modsecurity_skip_resp_body_filter: that variant skips the body filter but leavesfilter_need_in_memoryset (so the copy into memory remains) and never runs the RESPONSE_BODY phase; this PR does both and adds tests. Naming follows Add modsecurity_request_body directive to skip request body buffering (supersedes #356) #391 (modsecurity_request_body).return ret;on the last-buffer intervention path in the body filter untouched because fix: fail closed on swallowed WAF return values #384 owns that block.Origin: this change comes from a performance review of the connector done with Claude Fable 5.1 (Anthropic). The patch and its test were verified by building the module against nginx master with libmodsecurity 3.0.14 (PCRE2) and, with upstream CI's flags (
--without-pcre2 --with-http_v2_module --with-http_auth_request_module), against libmodsecurity 3.0.9 (PCRE1), then running the fulltests/modsecurity*.tsuite in both builds (16 files, 264 tests, all passing).Summary by CodeRabbit
New Features
modsecurity_response_bodydirective to control whether response bodies are inspected by ModSecurity.Documentation
Tests