mirror of
https://github.com/searxng/searxng.git
synced 2026-08-29 18:41:31 +00:00
[fix] py: (un)trusted proxies (#6556)
A missing condition allowed an attacker to mask their IP address from the server. This exploit can only be carried under specific client & server environments. Reported-by: Raffaele Forte <raffaele@backbox.org> Signed-off-by: Ivan Gabaldon <igabaldon@inetol.net>
This commit is contained in:
@@ -63,6 +63,20 @@ class ProxyFix:
|
|||||||
proxy_list: list[str] = cfg.get("botdetection.trusted_proxies", default=[])
|
proxy_list: list[str] = cfg.get("botdetection.trusted_proxies", default=[])
|
||||||
return [ip_network(net, strict=False) for net in proxy_list]
|
return [ip_network(net, strict=False) for net in proxy_list]
|
||||||
|
|
||||||
|
def is_trusted_proxy(
|
||||||
|
self,
|
||||||
|
addr: IPv4Address | IPv6Address | None,
|
||||||
|
trusted_proxies: list[IPv4Network | IPv6Network],
|
||||||
|
) -> bool:
|
||||||
|
if addr is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for net in trusted_proxies:
|
||||||
|
if addr.version == net.version and addr in net:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def trusted_remote_addr(
|
def trusted_remote_addr(
|
||||||
self,
|
self,
|
||||||
x_forwarded_for: list[IPv4Address | IPv6Address],
|
x_forwarded_for: list[IPv4Address | IPv6Address],
|
||||||
@@ -70,16 +84,8 @@ class ProxyFix:
|
|||||||
) -> str:
|
) -> str:
|
||||||
# always rtl
|
# always rtl
|
||||||
for addr in reversed(x_forwarded_for):
|
for addr in reversed(x_forwarded_for):
|
||||||
trust: bool = False
|
if not self.is_trusted_proxy(addr, trusted_proxies):
|
||||||
|
logger.debug("client address from X-Forwarded-For: %s", addr)
|
||||||
for net in trusted_proxies:
|
|
||||||
if addr.version == net.version and addr in net:
|
|
||||||
logger.debug("trust proxy %s (member of %s)", addr, net)
|
|
||||||
trust = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# client address
|
|
||||||
if not trust:
|
|
||||||
return addr.compressed
|
return addr.compressed
|
||||||
|
|
||||||
# fallback to first address
|
# fallback to first address
|
||||||
@@ -95,19 +101,21 @@ class ProxyFix:
|
|||||||
# in this function!
|
# in this function!
|
||||||
|
|
||||||
orig_remote_addr: str | None = environ.pop("REMOTE_ADDR")
|
orig_remote_addr: str | None = environ.pop("REMOTE_ADDR")
|
||||||
|
orig_remote_ip: IPv4Address | IPv6Address | None = None
|
||||||
|
|
||||||
# Validate the IPs involved in this game and delete all invalid ones
|
# Validate the IPs involved in this game and delete all invalid ones
|
||||||
# from the WSGI environment.
|
# from the WSGI environment.
|
||||||
|
|
||||||
if orig_remote_addr:
|
if orig_remote_addr:
|
||||||
try:
|
try:
|
||||||
addr = ip_address(orig_remote_addr)
|
orig_remote_ip = ip_address(orig_remote_addr)
|
||||||
if addr.version == 6 and addr.ipv4_mapped:
|
if orig_remote_ip.version == 6 and orig_remote_ip.ipv4_mapped:
|
||||||
addr = addr.ipv4_mapped
|
orig_remote_ip = orig_remote_ip.ipv4_mapped
|
||||||
orig_remote_addr = addr.compressed
|
orig_remote_addr = orig_remote_ip.compressed
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
logger.error("REMOTE_ADDR: %s / discard REMOTE_ADDR from WSGI environment", exc)
|
logger.error("REMOTE_ADDR: %s / discard REMOTE_ADDR from WSGI environment", exc)
|
||||||
orig_remote_addr = None
|
orig_remote_addr = None
|
||||||
|
orig_remote_ip = None
|
||||||
|
|
||||||
x_real_ip: str | None = environ.get("HTTP_X_REAL_IP")
|
x_real_ip: str | None = environ.get("HTTP_X_REAL_IP")
|
||||||
if x_real_ip:
|
if x_real_ip:
|
||||||
@@ -141,11 +149,13 @@ class ProxyFix:
|
|||||||
if not x_forwarded_for and not x_real_ip:
|
if not x_forwarded_for and not x_real_ip:
|
||||||
log_error_only_once("X-Forwarded-For nor X-Real-IP header is set!")
|
log_error_only_once("X-Forwarded-For nor X-Real-IP header is set!")
|
||||||
|
|
||||||
if x_forwarded_for and not trusted_proxies:
|
if x_forwarded_for or x_real_ip:
|
||||||
|
if not trusted_proxies:
|
||||||
log_error_only_once("missing botdetection.trusted_proxies config")
|
log_error_only_once("missing botdetection.trusted_proxies config")
|
||||||
# without trusted_proxies, this variable is useless for determining
|
|
||||||
# the real IP
|
if not self.is_trusted_proxy(orig_remote_ip, trusted_proxies):
|
||||||
x_forwarded_for = []
|
x_forwarded_for = []
|
||||||
|
x_real_ip = None
|
||||||
|
|
||||||
# securing the WSGI environment variables that are adjusted
|
# securing the WSGI environment variables that are adjusted
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user