mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-11 05:35:25 +03:00
use x-forwarded-for to rate limit login attempts by ip
This commit is contained in:
parent
6d6a54c5ae
commit
35f02bd505
@ -7,7 +7,7 @@ proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-URI $request_uri;
|
||||
proxy_set_header X-Forwarded-Ssl on;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
## Basic Proxy Configuration
|
||||
|
||||
@ -87,8 +87,9 @@ def create_app(
|
||||
app.camera_error_image = None
|
||||
app.stats_emitter = stats_emitter
|
||||
app.jwt_token = get_jwt_secret() if frigate_config.auth.enabled else None
|
||||
# initialize the rate limiter for the login endpoint
|
||||
# update the request_address with the x-forwarded-for header from nginx
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)
|
||||
# initialize the rate limiter for the login endpoint
|
||||
limiter.init_app(app)
|
||||
if frigate_config.auth.failed_login_rate_limit is None:
|
||||
limiter.enabled = False
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
import base64
|
||||
import hashlib
|
||||
import ipaddress
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@ -13,7 +14,6 @@ from pathlib import Path
|
||||
|
||||
from flask import Blueprint, current_app, jsonify, make_response, request
|
||||
from flask_limiter import Limiter
|
||||
from flask_limiter.util import get_remote_address
|
||||
from joserfc import jwt
|
||||
from peewee import DoesNotExist
|
||||
|
||||
@ -24,8 +24,51 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
AuthBp = Blueprint("auth", __name__)
|
||||
|
||||
|
||||
def get_remote_addr():
|
||||
route = list(reversed(request.headers.get("x-forwarded-for").split(",")))
|
||||
logger.debug(f"IP Route: {[r for r in route]}")
|
||||
trusted_proxies = []
|
||||
for proxy in current_app.frigate_config.auth.trusted_proxies:
|
||||
try:
|
||||
network = ipaddress.ip_network(proxy)
|
||||
except ValueError:
|
||||
logger.warn(f"Unable to parse trusted network: {proxy}")
|
||||
trusted_proxies.append(network)
|
||||
|
||||
# return the first remote address that is not trusted
|
||||
for addr in route:
|
||||
ip = ipaddress.ip_address(addr.strip())
|
||||
logger.debug(f"Checking {ip} (v{ip.version})")
|
||||
trusted = False
|
||||
for trusted_proxy in trusted_proxies:
|
||||
logger.debug(
|
||||
f"Checking against trusted proxy: {trusted_proxy} (v{trusted_proxy.version})"
|
||||
)
|
||||
if trusted_proxy.version == 4:
|
||||
ipv4 = ip.ipv4_mapped if ip.version == 6 else ip
|
||||
if ipv4 in trusted_proxy:
|
||||
trusted = True
|
||||
logger.debug(f"Trusted: {str(ip)} by {str(trusted_proxy)}")
|
||||
break
|
||||
elif trusted_proxy.version == 6 and ip.version == 6:
|
||||
if ip in trusted_proxy:
|
||||
trusted = True
|
||||
logger.debug(f"Trusted: {str(ip)} by {str(trusted_proxy)}")
|
||||
break
|
||||
if trusted:
|
||||
logger.debug(f"{ip} is trusted")
|
||||
continue
|
||||
else:
|
||||
logger.debug(f"First untrusted IP: {str(ip)}")
|
||||
return str(ip)
|
||||
|
||||
# if there wasn't anything in the route, just return the default
|
||||
return request.remote_addr or "127.0.0.1"
|
||||
|
||||
|
||||
limiter = Limiter(
|
||||
lambda: get_remote_address,
|
||||
get_remote_addr,
|
||||
storage_uri="memory://",
|
||||
)
|
||||
|
||||
|
||||
@ -136,6 +136,10 @@ class AuthConfig(FrigateBaseModel):
|
||||
default="1/second;5/minute;20/hour",
|
||||
title="Rate limits for failed login attempts.",
|
||||
)
|
||||
trusted_proxies: Optional[List[str]] = Field(
|
||||
default=[],
|
||||
title="Trusted proxies for determining IP address to rate limit",
|
||||
)
|
||||
# As of Feb 2023, OWASP recommends 600000 iterations for PBKDF2-SHA256
|
||||
hash_iterations: int = Field(default=600000, title="Password hash iterations")
|
||||
|
||||
|
||||
@ -59,7 +59,7 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const err = error as AxiosError;
|
||||
if (err.response?.status === 429) {
|
||||
toast.error("Exceeded rate limit. Try again in 1 minute.", {
|
||||
toast.error("Exceeded rate limit. Try again later.", {
|
||||
position: "top-center",
|
||||
});
|
||||
} else if (err.response?.status === 400) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user