pjfanning opened a new pull request, #1371:
URL: https://github.com/apache/pekko-http/pull/1371

   > **Draft for discussion.** This ports akka/akka-http#4324, which is an 
**alternative** to the rapid reset protection Pekko HTTP already has 
(`frame-type-throttle`, added in #394). Before this goes further we need to 
decide how the two should coexist, in particular **what should happen when both 
are enabled**.
   
   ### Motivation
   akka/akka-http#4324 protects against HTTP/2 Rapid Reset 
([CVE-2023-44487](https://nvd.nist.gov/vuln/detail/CVE-2023-44487)) by counting 
RST_STREAM frames per connection and closing the connection with 
`ENHANCE_YOUR_CALM` when a limit is exceeded. Pekko HTTP independently added 
`pekko.http.server.http2.frame-type-throttle` for the same attack, so the two 
mechanisms overlap.
   
   ### How the two mechanisms compare
   
   | | existing `frame-type-throttle` (default **on**) | `max-resets` from 
akka/akka-http#4324 (this PR, default **off**) |
   |---|---|---|
   | Algorithm | token bucket via `throttle(..., ThrottleMode.Enforcing)` | 
counter in a fixed window |
   | Default limit | burst 100, refill 100 per 1s | akka-http: 400 per 10s; 
here: disabled (`max-resets = 0`) |
   | Frame types | configurable (default `reset`) | RST_STREAM only |
   | When exceeded | `RateExceededException` → `errorHandling` logs at 
**ERROR** and sends `GOAWAY(INTERNAL_ERROR)` | `Http2ProtocolException` → 
logged at **DEBUG**, `GOAWAY(ENHANCE_YOUR_CALM)` (the code RFC 9113 provides 
for a peer "exhibiting a behavior that might be generating excessive load") |
   
   ### What happens if both are enabled
   `RSTFrameLimit` sits directly above frame parsing, so it sees incoming 
frames before the throttle. Each limit is checked independently and **whichever 
is exceeded first closes the connection**, so the effective limit is the 
stricter of the two, and the client sees a different error code depending on 
which one tripped:
   - a fast burst over the throttle's burst size, but under `max-resets`, gets 
`GOAWAY(INTERNAL_ERROR)` and an ERROR log line 
(`Http2ServerMaxResetsAndThrottleSpec`);
   - a burst under the throttle's burst size but over `max-resets`, or a 
sustained rate below the throttle's refill rate that adds up to more than 
`max-resets` in the window, gets `GOAWAY(ENHANCE_YOUR_CALM)` and a DEBUG log 
line (`Http2ServerMaxResetsSpec`).
   
   ### Questions for reviewers
   1. **Keep both, or pick one?** Options:
      a. keep both, `max-resets` opt-in (this PR as is);
      b. keep both, enable `max-resets` by default as in akka-http (changes 
behaviour for existing users: connections with a sustained moderate reset rate 
start getting closed);
      c. switch the default protection to `max-resets` and make the throttle's 
default `frame-types = []`;
      d. don't add `max-resets`, but make the throttle fail with 
`Http2ProtocolException(ENHANCE_YOUR_CALM)` instead of `INTERNAL_ERROR` and an 
ERROR log.
   2. If both stay, should enabling both be **rejected or warned about** at 
settings validation, or documented as "the stricter limit wins"?
   3. Independently of this PR, the throttle reports an attacker-provoked 
condition as `INTERNAL_ERROR` and logs it at ERROR level. `max-resets` (and 
other protocol limits such as the HPACK header-list size) use 
`ENHANCE_YOUR_CALM` at DEBUG. Worth aligning?
   4. While writing the tests I found that the existing 
`Http2ServerEnableFrameTypeThrottleSpec` / 
`Http2ServerDisableFrameTypeThrottleSpec` send RST_STREAM for stream 1 without 
opening it. That is an RST on an idle stream, which the server answers with 
`GOAWAY(PROTOCOL_ERROR)`. Neither spec checks what the server sends, so they 
don't actually exercise a rapid reset. The new specs open each stream with 
HEADERS and then reset it, as in akka-http's test. Should the throttle specs be 
fixed in a separate PR?
   
   ### Modification
   - New settings `pekko.http.server.http2.max-resets` (default `0` = disabled) 
and `max-resets-interval` (default `10s`), with Scala (`maxResets`, 
`maxResetsInterval`, `withMaxResets`, `withMaxResetsInterval`) and Java 
(`getMaxResets`, `getMaxResetsInterval`, `withMaxResets`, 
`withMaxResetsInterval(java.time.Duration)`) accessors, all `@since 2.0.0`. 
`reference.conf` documents the interaction with `frame-type-throttle`.
   - `RSTFrameLimit` ported from akka-http (keeping its Lightbend header under 
the Pekko "derived from Akka" header), added to the server stack only when 
`max-resets > 0`.
   - `http2-max-resets.excludes`: MiMa filters for the abstract methods added 
to the `@DoNotInherit` `Http2ServerSettings`. Its license header is copied from 
the sibling excludes files.
   
   ### Result
   Users can opt in to a reset limit that closes abusive connections with 
`ENHANCE_YOUR_CALM`. Nothing changes by default.
   
   ### Tests
   - `sbt "http2-tests/Test/testOnly 
org.apache.pekko.http.impl.engine.http2.Http2ServerMaxResets*"`: 5 passed on 
Scala 2.13 and 3.3.8 (limit alone, at-limit, limit exceeded before the 
throttle, throttle exceeded before the limit, default disabled)
   - Without the `Http2Blueprint` wiring, both `ENHANCE_YOUR_CALM` tests fail 
(directional)
   - `sbt "http2-tests/Test/testOnly 
org.apache.pekko.http.impl.engine.http2.Http2Server*FrameTypeThrottleSpec"`: 
pass
   - `sbt http-core/mimaReportBinaryIssues`: pass
   - `scalafmt`: no changes
   
   ### References
   Port of akka/akka-http#4324 (Refs akka/akka-http#4323), which is Apache 2.0 
now that the Akka HTTP 10.6.0 license change date (2026-10-23) has passed. 
Copied code: `RSTFrameLimit.scala` from akka-http v10.6.0; the reset pattern in 
`Http2ServerMaxResetsSpec` follows akka-http's `Http2ServerSpec` test. Existing 
mechanism: #394.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to