mirror of
https://github.com/searxng/searxng.git
synced 2025-07-24 13:49:26 +02:00
[fix] limiter: replace real_ip by IPv4/v6 network
Closes: https://github.com/searxng/searxng/issues/2477 Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
parent
38431d2e14
commit
281e36f4b7
12 changed files with 208 additions and 106 deletions
|
@ -6,7 +6,7 @@ Method ``link_token``
|
|||
|
||||
The ``link_token`` method evaluates a request as :py:obj:`suspicious
|
||||
<is_suspicious>` if the URL ``/client<token>.css`` is not requested by the
|
||||
client. By adding a random component (the token) in the URL a bot can not send
|
||||
client. By adding a random component (the token) in the URL, a bot can not send
|
||||
a ping by request a static URL.
|
||||
|
||||
.. note::
|
||||
|
@ -35,6 +35,11 @@ And in the HTML template from flask a stylesheet link is needed (the value of
|
|||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from ipaddress import (
|
||||
IPv4Network,
|
||||
IPv6Network,
|
||||
)
|
||||
|
||||
import string
|
||||
import random
|
||||
|
@ -43,7 +48,11 @@ import flask
|
|||
from searx import logger
|
||||
from searx import redisdb
|
||||
from searx.redislib import secret_hash
|
||||
from ._helpers import get_real_ip
|
||||
|
||||
from ._helpers import (
|
||||
get_network,
|
||||
get_real_ip,
|
||||
)
|
||||
|
||||
TOKEN_LIVE_TIME = 600
|
||||
"""Livetime (sec) of limiter's CSS token."""
|
||||
|
@ -60,29 +69,26 @@ TOKEN_KEY = 'SearXNG_limiter.token'
|
|||
logger = logger.getChild('botdetection.link_token')
|
||||
|
||||
|
||||
def is_suspicious(request: flask.Request, renew: bool = False):
|
||||
"""Checks if there is a valid ping for this request, if not this request is
|
||||
rated as *suspicious*. If a valid ping exists and argument ``renew`` is
|
||||
``True`` the expire time of this ping is reset to :py:obj:`PING_LIVE_TIME`.
|
||||
def is_suspicious(network: IPv4Network | IPv6Network, request: flask.Request, renew: bool = False):
|
||||
"""Checks whether a valid ping is exists for this (client) network, if not
|
||||
this request is rated as *suspicious*. If a valid ping exists and argument
|
||||
``renew`` is ``True`` the expire time of this ping is reset to
|
||||
:py:obj:`PING_LIVE_TIME`.
|
||||
|
||||
"""
|
||||
redis_client = redisdb.client()
|
||||
if not redis_client:
|
||||
return False
|
||||
|
||||
ping_key = get_ping_key(request)
|
||||
ping_key = get_ping_key(network, request)
|
||||
if not redis_client.get(ping_key):
|
||||
logger.warning(
|
||||
"missing ping (IP: %s) / request: %s",
|
||||
get_real_ip(request),
|
||||
ping_key,
|
||||
)
|
||||
logger.warning("missing ping (IP: %s) / request: %s", network.compressed, ping_key)
|
||||
return True
|
||||
|
||||
if renew:
|
||||
redis_client.set(ping_key, 1, ex=PING_LIVE_TIME)
|
||||
|
||||
logger.debug("found ping for client request: %s", ping_key)
|
||||
logger.debug("found ping for (client) network %s -> %s", network.compressed, ping_key)
|
||||
return False
|
||||
|
||||
|
||||
|
@ -92,27 +98,31 @@ def ping(request: flask.Request, token: str):
|
|||
The expire time of this ping-key is :py:obj:`PING_LIVE_TIME`.
|
||||
|
||||
"""
|
||||
from . import limiter # pylint: disable=import-outside-toplevel, cyclic-import
|
||||
|
||||
redis_client = redisdb.client()
|
||||
if not redis_client:
|
||||
return
|
||||
if not token_is_valid(token):
|
||||
return
|
||||
ping_key = get_ping_key(request)
|
||||
logger.debug("store ping for: %s", ping_key)
|
||||
|
||||
cfg = limiter.get_cfg()
|
||||
real_ip = get_real_ip(request)
|
||||
network = get_network(real_ip, cfg)
|
||||
|
||||
ping_key = get_ping_key(network, request)
|
||||
logger.debug("store ping_key for (client) network %s (IP %s) -> %s", network.compressed, real_ip, ping_key)
|
||||
redis_client.set(ping_key, 1, ex=PING_LIVE_TIME)
|
||||
|
||||
|
||||
def get_ping_key(request: flask.Request):
|
||||
"""Generates a hashed key that fits (more or less) to a client (request).
|
||||
At least X-Forwarded-For_ is needed to be able to assign the request to an
|
||||
IP.
|
||||
|
||||
"""
|
||||
def get_ping_key(network: IPv4Network | IPv6Network, request: flask.Request) -> str:
|
||||
"""Generates a hashed key that fits (more or less) to a *WEB-browser
|
||||
session* in a network."""
|
||||
return (
|
||||
PING_KEY
|
||||
+ "["
|
||||
+ secret_hash(
|
||||
get_real_ip(request) + request.headers.get('Accept-Language', '') + request.headers.get('User-Agent', '')
|
||||
network.compressed + request.headers.get('Accept-Language', '') + request.headers.get('User-Agent', '')
|
||||
)
|
||||
+ "]"
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue