Explorar el Código

docs: mark SEC_REVIEW F25 as fixed in 33e9198

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa hace 4 días
padre
commit
5f05743c4b
Se han modificado 1 ficheros con 37 adiciones y 1 borrados
  1. 37 1
      doc/SEC_REVIEW.md

+ 37 - 1
doc/SEC_REVIEW.md

@@ -11,7 +11,7 @@
 >
 > Each finding is referenced as **F<N>** for later citation.
 >
-> **Findings rolled up:** 5 sev-3 (5 fixed, 0 open), 27 sev-2 (15 fixed, 12 open), 42 sev-1.
+> **Findings rolled up:** 5 sev-3 (5 fixed, 0 open), 27 sev-2 (16 fixed, 11 open), 42 sev-1.
 
 ---
 
@@ -886,6 +886,42 @@
   `INTERNAL_JOB_TOKEN` is still required, but the network-layer
   defense is bypassable on tenant-shared docker hosts.
 - **Severity: 2**
+- **Status:** Fixed. Three layers tighten the gate to loopback-only by
+  default; everything else has to opt in explicitly:
+  1. **Caddy `trusted_proxies` narrowed.** `api/docker/Caddyfile`
+     replaces `trusted_proxies static private_ranges` with
+     `trusted_proxies static {$TRUSTED_PROXIES:127.0.0.1/32 ::1/128}`.
+     With no env override, only loopback is treated as a "real proxy"
+     for XFF rewriting — so a non-loopback peer can no longer forge
+     `REMOTE_ADDR=127.0.0.1` via `X-Forwarded-For`. Operators behind a
+     genuine reverse proxy set `TRUSTED_PROXIES` to that proxy's CIDR.
+  2. **Caddy `@internal` matcher narrowed.** The `remote_ip` allowlist
+     for `/internal/*` is now `127.0.0.1/32 ::1/128` only — the wide
+     RFC1918 entries (`172.16.0.0/12`, `10.0.0.0/8`, `192.168.0.0/16`)
+     are gone. Mirrored on the opposite `not remote_ip` deny rule.
+  3. **PHP `InternalNetworkMiddleware` constructor-driven.** The
+     hardcoded RFC1918 list is gone; the constructor now takes an
+     optional CIDR list and falls back to
+     `DEFAULT_ALLOWED_CIDRS = ['127.0.0.1/32', '::1/128']`. The DI
+     container reads `INTERNAL_CIDR_ALLOWLIST` from env (parsed by a
+     new `parseCidrList()` helper that fails-closed on invalid input)
+     and passes the result to the middleware. Operators with a host-
+     cron VM on a private bridge add their CIDR via env and Caddyfile.
+  4. **Sidecar scheduler joins the api's network namespace.**
+     `compose.scheduler.yml` switches to `network_mode: "service:api"`
+     and `scheduler.crontab` posts to `http://localhost:8081/...`
+     instead of `http://api:8081/...`. The scheduler's call now
+     arrives on `127.0.0.1` inside the shared netns, satisfying the
+     loopback-only gate without weakening it for actual neighbours.
+     SPEC §7 ("Scheduling") and §6 ("Internal endpoints") updated to
+     match.
+  Regression tests in `api/tests/Unit/Http/InternalNetworkMiddlewareTest.php`:
+  the data provider now expects RFC1918 sources to be **rejected** under
+  the default; new cases cover (a) `null` / `[]` falling back to the
+  loopback default, (b) a custom `172.20.0.5/32` allowlist admitting only
+  that exact source, (c) invalid CIDRs failing-closed at construction,
+  and (d) the `parseCidrList()` env-parser accepting comma- and
+  whitespace-separated input while throwing on garbage.
 
 ### F26 — JsonErrorHandler can leak raw exception messages in production
 - **File:** `api/src/Infrastructure/Http/JsonErrorHandler.php:53-82`