rate_limit: Add interface to override rate limiting rules.

This commit is contained in:
Mateusz Mandera 2022-11-05 23:55:11 +01:00 committed by Tim Abbott
parent 7c4da60b53
commit 34a0139c2b
4 changed files with 96 additions and 29 deletions

View File

@ -275,6 +275,46 @@ strength allowed is controlled by two settings in
[smokescreen-setup]: deployment.md#customizing-the-outgoing-http-proxy
[proxy.enable_for_camo]: deployment.md#enable_for_camo
## Rate limiting
Zulip has built-in rate limiting of login attempts, all access to the
API, as well as certain other types of actions that may be involved in
abuse. For example, the email confirmation flow, by its nature, needs
to allow sending an email to an email address that isn't associated
with an existing Zulip account. Limiting the ability of users to
trigger such emails helps prevent bad actors from damaging the spam
reputation of a Zulip server by sending confirmation emails to random
email addresses.
The default rate limiting rules for a Zulip server will change as we improve
the product. A server administrator can browse the current rules using
`/home/zulip/deployments/current/scripts/get-django-setting
RATE_LIMITING_RULES`; or with comments by reading
`DEFAULT_RATE_LIMITING_RULES` in `zproject/default_settings.py`.
Server administrators can tweak rate limiting in the following ways in
`/etc/zulip/settings.py`:
- The `RATE_LIMITING` setting can be set to `False` to completely
disable all rate-limiting.
- The `RATE_LIMITING_RULES` setting can be used to override specific
rules. See the comment in the file for more specific details on how
to do it. After changing the setting, we recommend using
`/home/zulip/deployments/current/scripts/get-django-setting
RATE_LIMITING_RULES` to verify your changes. You can then restart
the Zulip server with `scripts/restart-server` to have the new
configuration take effect.
- The `RATE_LIMIT_TOR_TOGETHER` setting can be set to `True` to group all
known exit nodes of [TOR](https://www.torproject.org/) together for purposes
of IP address limiting. Since traffic from a client using TOR is distributed
across its exit nodes, without enabling this setting, TOR can otherwise be
used to avoid IP-based rate limiting. The updated list of TOR exit nodes
is refetched once an hour.
See also our [API documentation on rate limiting][rate-limit-api].
[rate-limit-api]: https://zulip.com/api/rest-error-handling#rate-limit-exceeded
## Final notes and security response
If you find some aspect of Zulip that seems inconsistent with this

View File

@ -30,6 +30,7 @@ from .configured_settings import (
CUSTOM_HOME_NOT_LOGGED_IN,
DEBUG,
DEBUG_ERROR_REPORTING,
DEFAULT_RATE_LIMITING_RULES,
EMAIL_BACKEND,
EMAIL_HOST,
ERROR_REPORTING,
@ -42,6 +43,7 @@ from .configured_settings import (
LOCAL_UPLOADS_DIR,
MEMCACHED_LOCATION,
MEMCACHED_USERNAME,
RATE_LIMITING_RULES,
REALM_HOSTS,
REGISTER_LINK_DISABLED,
REMOTE_POSTGRES_HOST,
@ -358,34 +360,8 @@ CACHES: Dict[str, Dict[str, object]] = {
# REDIS-BASED RATE LIMITING CONFIGURATION
########################################################################
RATE_LIMITING_RULES = {
"api_by_user": [
(60, 200), # 200 requests max every minute
],
"api_by_ip": [
(60, 100),
],
"api_by_remote_server": [
(60, 1000),
],
"authenticate_by_username": [
(1800, 5), # 5 failed login attempts within 30 minutes
],
"email_change_by_user": [
(3600, 2), # 2 per hour
(86400, 5), # 5 per day
],
"password_reset_form_by_email": [
(3600, 2), # 2 reset emails per hour
(86400, 5), # 5 per day
],
"sends_email_by_ip": [
(86400, 5),
],
"spectator_attachment_access_by_file": [
(86400, 1000), # 1000 per day per file
],
}
# Merge any local overrides with the default rules.
RATE_LIMITING_RULES = {**DEFAULT_RATE_LIMITING_RULES, **RATE_LIMITING_RULES}
# List of domains that, when applied to a request in a Tornado process,
# will be handled with the separate in-memory rate limiting backend for Tornado,

View File

@ -1,6 +1,6 @@
import os
from email.headerregistry import Address
from typing import TYPE_CHECKING, Any, Dict, List, Optional
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
from scripts.lib.zulip_tools import deport
from zproject.settings_types import JwtAuthKey, OIDCIdPConfigDict, SAMLIdPConfigDict
@ -198,6 +198,39 @@ RATE_LIMIT_TOR_TOGETHER = False
SEND_LOGIN_EMAILS = True
EMBEDDED_BOTS_ENABLED = False
DEFAULT_RATE_LIMITING_RULES = {
"api_by_user": [
(60, 200), # 200 requests max every minute
],
"api_by_ip": [
(60, 100),
],
"api_by_remote_server": [
(60, 1000),
],
"authenticate_by_username": [
(1800, 5), # 5 failed login attempts within 30 minutes
],
"email_change_by_user": [
(3600, 2), # 2 per hour
(86400, 5), # 5 per day
],
"password_reset_form_by_email": [
(3600, 2), # 2 reset emails per hour
(86400, 5), # 5 per day
],
"sends_email_by_ip": [
(86400, 5),
],
"spectator_attachment_access_by_file": [
(86400, 1000), # 1000 per day per file
],
}
# Rate limiting defaults can be individually overridden by adding
# entries in this object, which is merged with
# DEFAULT_RATE_LIMITING_RULES.
RATE_LIMITING_RULES: Dict[str, List[Tuple[int, int]]] = {}
# Two factor authentication is not yet implementation-complete
TWO_FACTOR_AUTHENTICATION_ENABLED = False

View File

@ -764,6 +764,24 @@ CAMO_URI = "/external_content/"
## Controls whether Zulip will rate-limit user requests.
# RATE_LIMITING = True
## Entries in this dictionary will override Zulip's default rate
## limits. Rules which are not explicitly overridden here
## will be as default. View the current rules using:
## /home/zulip/deployments/current/scripts/get-django-setting RATE_LIMITING_RULES
##
## The limits are tuples of a number of seconds and a number of
## requests allowed over that many seconds. If multiple tuples are
## given in a rule, a request breaching any of them will trigger a
## rate-limited response to the client. For example, to change the
## limits for total API requests by each user to be at most 100
## requests per minute, and at most 200 requests per hour, add:
## "api_by_user": [(60, 100), (3600, 200)],
# RATE_LIMITING_RULES = {
# "api_by_ip": [
# (60, 100),
# ],
# }
## Fetch TOR exit node list every hour, and group all TOR exit nodes
## together into one bucket when applying rate-limiting.
# RATE_LIMIT_TOR_TOGETHER = False