Commit e7eb105
authored
ratelimits: stricter() should always prefer denied decisions (#8674)
In ratelimits.BatchSpend(), stricter() selects the most restrictive
decision across all rate limits in a batch. It compares decisions solely
by retryIn, assuming a longer wait is always stricter, and never checks
the allowed field. An allowed decision with a high retryIn beats a
denied decision with a low retryIn, causing the batch to return allowed:
true despite one or more limits denying the request.
This can occur at NewOrder time via checkNewOrderLimits(), which
batches:
- NewOrdersPerAccount (check-and-spend, emissionInterval=36s)
- FailedAuthorizationsPerDomainPerAccount (check-only,
emissionInterval=12min)
- CertificatesPerDomain (check-only, emissionInterval=3.36h)
- CertificatesPerFQDNSet (check-only, emissionInterval=33.6h)
A subscriber who exhausts their 300 new order quota gets a denied
retryIn of at most 36s. If any check-only limit in the same batch has
exactly 1 token remaining at request time, that last token produces an
allowed decision with retryIn equal to the limit's full emission
interval, all of which dwarf 36s. Because check-only transactions never
deduct from the bucket, the token is never consumed and the same
oversized retryIn wins on every subsequent request. Orders can pile up
well past the 300 limit until countCertificateIssued() runs a separate
spend-only batch after issuance.
This can also occur for IPv6 clients at NewAccount time via
checkNewAccountLimits(), which batches:
- NewRegistrationsPerIPAddress (check-and-spend,emissionInterval =
18min)
- NewRegistrationsPerIPv6Range (check-and-spend,emissionInterval =
21.6s)
These are both check-and-spend with the same 3 hour period. The emission
intervals differ (18min vs 21.6s), so the bug is technically possible
here too. For IPv6, the per-IP limit (10) will almost always exhaust
before the /48 range limit (500), so the reverse scenario (per-range
denied, per-IP allowed) is unlikely but not impossible if many IPs in
the same /48 are registering. If NewRegistrationsPerIPv6Range denies
(retryIn = 21.6s) while NewRegistrationsPerIPAddress allows with 1
remaining (retryIn = 18min), stricter() picks the allowed decision. Both
transactions are check-and-spend, so the request that sneaks through
deducts from the per-IP bucket, exhausting it. After that, both limits
deny and the bug no longer triggers, unlike NewOrder.
Restructure stricter() so denied decisions are always picked over
allowed ones regardless of retryIn. The retryIn and remaining
comparisons now serve only as tiebreakers within the same allowed/denied
category.1 parent f05103a commit e7eb105
2 files changed
+79
-9
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
245 | 247 | | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
250 | 261 | | |
251 | | - | |
252 | 262 | | |
253 | 263 | | |
254 | 264 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
610 | 610 | | |
611 | 611 | | |
612 | 612 | | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
0 commit comments