CreaRack-SL

IP real del visitante a prueba de Cloudflare (v1.45.13)

Resumen

Preparación del código de CreaRack para proxificar el apex crearack.com a través de Cloudflare (activar WAF + protección anti-DDoS). La corrección principal está en la función _get_client_ip de core/auth_api.py: tras la proxificación, el encabezado X-Forwarded-For contiene una cadena "cliente, cf-edge" en lugar de un único valor, y el helper debe leer el primero (cliente real) no el último (IP del edge de Cloudflare).

Actualización v1.156.0 (24-09-2026): la lógica de este helper se consolidó en core.middleware.rate_limit.get_client_ip (ver sección abajo) y cambió de fuente primaria. Ver [[entity—core—middleware—rate-limit]] para el middleware que lo usa.


Contexto de la iniciativa (jul-2026)

Motivación (Security Center de Cloudflare, sesión 2026-07-07): el dominio crearack.com entraba directo al servidor Hetzner sin pasar por el escudo de Cloudflare (sin WAF/anti-DDoS, IP del servidor visible). Plan: preparar el código (este PR), Transform Rule en CF que reescribe XFF en el edge, Traefik con trustedIPs, flip del registro A a proxied.

El cambio técnico (v1.45.13, jul-2026)

core/auth_api.py::_get_client_ip

Antes (v1.45.12): parts[-1] if len(parts) > 1 else parts[0] (último salto — tomaba la IP de Cloudflare). Ahora (v1.45.13): xff.split(",")[0].strip() (primer salto — el cliente real).

Por qué: con Cloudflare, X-Forwarded-For: "cliente, 172.71.10.10" (dos valores); el código antiguo devolvía el edge, no el cliente, y eso llegaba mal a los logs de auditoría de login/passkeys.

Seguridad (jul-2026): el primer valor no podía ser spoofed porque la Transform Rule de CF sobrescribe XFF en el edge con el valor real — un supuesto de infraestructura fuera del repo, no del código. Ver el endurecimiento v1.156.0 abajo, que deja de depender solo de esa regla.

Tests (jul-2026): tests/test_client_ip.py (7 tests, cadena CF / un salto / sin XFF, en auth_api y signals) y tests/test_admin_paths.py (2 tests, acceso a /admin vía cadena CF). 16/16 en verde en local.

Alineamiento (jul-2026): core/signals.py, portal.py y api/admin.py ya cogían el primero o se alinearon — pero cada uno con su PROPIA copia de la lógica.


Hardening v1.156.0 — mega-auditoría B-30 (24-09-2026, PR #603, commit 5d06aef1)

El problema que quedaba: “primer valor de XFF” (jul-2026) depende de que la Transform Rule de Cloudflare siga viva. Cloudflare expone una cabecera más directa que no hace falta transformar: CF-Connecting-IP, que el edge escribe SIEMPRE con la IP real del visitante (la fija, no la concatena).

El cambio: toda la lógica se consolida en un ÚNICO helper, core.middleware.rate_limit.get_client_ip(request, trusted_proxy_nets=None) — ya no cada módulo con su copia de _get_client_ip. Solo si el salto directo (REMOTE_ADDR) es un proxy de confianza se leen cabeceras: 1º CF-Connecting-IP; 2º si falta, el primer valor de X-Forwarded-For (defensa en profundidad, la Transform Rule sigue viva). Sin Cloudflare delante (dev/local): REMOTE_ADDR de siempre. Valores que no son una IP válida se ignoran.

Quién lo usa ahora: core/middleware/rate_limit.py (RateLimitMiddleware.get_client_ip pasa a ser un wrapper de una línea — ver [[entity—core—middleware—rate-limit]]), impersonate_start, core/auth_api.py y core/signals.py: los cuatro sitios que jul-2026 había “alineado” por separado ahora comparten una sola implementación.

Diferencia con el criterio de jul-2026: antes, “primer valor de XFF” dependía de un supuesto de infraestructura (la Transform Rule). Ahora CF-Connecting-IP es la fuente primaria porque Cloudflare la fija (no hay “salto” que interpretar mal), y XFF queda solo como respaldo.

Límite honesto: sin Cloudflare delante el comportamiento sigue siendo REMOTE_ADDR; core/middleware/admin_paths.py y signage/services/publish_misses.py tienen su propia lectura de IP y NO se tocaron en esta ronda.

Tests: no hay fichero dedicado a esta consolidación; la cobertura previa (tests/test_client_ip.py, tests/test_admin_paths.py) sigue pasando porque el comportamiento sin Cloudflare no cambia.

Véase también

  • [[entity—core—service—log-action]]
  • [[concept—security—credential-encryption]]
  • [[entity—core—service—has-permission]]
  • [[entity—core—middleware—rate-limit]]