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]
