Summary
BREACH needs three conditions on the same response: HTTP compression, attacker-controlled input reflected in the body, and a secret in the body (CSRF tokens, session data). Dynamic HTML and API responses can meet all three; static assets (text/css, application/javascript, image/svg+xml, fonts, …) are identical for every user and safe to compress.
Response compression is currently an all-or-nothing global switch: response.compression.threshold compresses every eligible response above the threshold (default 0 = everything), regardless of content type. The only way to mitigate compression-based side-channel attacks like BREACH is to disable compression entirely (-1), paying the full bandwidth cost.
Proposal
Add a MIME allowlist for response compression, e.g. a global response.compression.mime.types and/or a per-listener listener.<i>.compressionmimetypes, so that only listed content types are compressed. A sane default allowlist (static text assets, no text/html/application/json) could be applied on TLS listeners.
Implementation notes
Reactor Netty's compress(int) fixes the compression rule at listener build time. Per-response decisions (where Content-Type is known) require the compress(BiPredicate<HttpServerRequest, HttpServerResponse>) variant, evaluated at response write time. The two variants compose: compress(int) sets minCompressionSize, compress(BiPredicate) sets compressPredicate, and HttpTrafficHandler evaluates both (verified against Reactor Netty 1.2.6 docs and source).
If a per-listener property is introduced, consider aligning response.compression.threshold with a matching listener.<i>.compressionthreshold (global + listener-specific overrides, as already done for other settings).
Summary
BREACH needs three conditions on the same response: HTTP compression, attacker-controlled input reflected in the body, and a secret in the body (CSRF tokens, session data). Dynamic HTML and API responses can meet all three; static assets (
text/css,application/javascript,image/svg+xml, fonts, …) are identical for every user and safe to compress.Response compression is currently an all-or-nothing global switch:
response.compression.thresholdcompresses every eligible response above the threshold (default0= everything), regardless of content type. The only way to mitigate compression-based side-channel attacks like BREACH is to disable compression entirely (-1), paying the full bandwidth cost.Proposal
Add a MIME allowlist for response compression, e.g. a global
response.compression.mime.typesand/or a per-listenerlistener.<i>.compressionmimetypes, so that only listed content types are compressed. A sane default allowlist (static text assets, notext/html/application/json) could be applied on TLS listeners.Implementation notes
Reactor Netty's
compress(int)fixes the compression rule at listener build time. Per-response decisions (whereContent-Typeis known) require thecompress(BiPredicate<HttpServerRequest, HttpServerResponse>)variant, evaluated at response write time. The two variants compose:compress(int)setsminCompressionSize,compress(BiPredicate)setscompressPredicate, andHttpTrafficHandlerevaluates both (verified against Reactor Netty 1.2.6 docs and source).If a per-listener property is introduced, consider aligning
response.compression.thresholdwith a matchinglistener.<i>.compressionthreshold(global + listener-specific overrides, as already done for other settings).