|
|
@@ -654,7 +654,37 @@ note. Do not delete entries — they're history.
|
|
|
|
|
|
### R01-N19 — Strict CSP has no `report-uri` / `report-to`
|
|
|
- **Severity**: MEDIUM (operational visibility).
|
|
|
-- **Status**: open.
|
|
|
+- **Status**: fixed-in-`f59f368` — went with `report-uri` only (CSP
|
|
|
+ Level 1/2 directive, still honoured by every current browser; CSP3
|
|
|
+ `report-to` would have needed a `Reporting-Endpoints` response
|
|
|
+ header on every page and a second JSON parser for the
|
|
|
+ `application/reports+json` shape, neither cheap for the marginal
|
|
|
+ gain). `App\Http\FatalErrorHandler::CSP` gained
|
|
|
+ `report-uri /csp-report`. New public route `POST /csp-report`
|
|
|
+ routes to `App\Controllers\CspReportController::report`, which
|
|
|
+ body-caps at `MAX_BODY_BYTES = 16 * 1024` (real CSP reports are
|
|
|
+ well under 1 KiB; the cap is generous enough to never reject
|
|
|
+ legit reports, tight enough that a hostile client can't pump
|
|
|
+ megabytes of garbage into `audit_log`). The legacy
|
|
|
+ `{"csp-report": {...}}` envelope is unwrapped via the pure-static
|
|
|
+ `extractReport(string): ?array` helper; bare `{...}` shapes are
|
|
|
+ also accepted; top-level lists / scalars / non-JSON return null.
|
|
|
+ The endpoint is anonymous: no session, no CSRF — a browser fires
|
|
|
+ reports without session context most of the time, and a forged
|
|
|
+ report only costs one audit row (bounded by the cap). Always
|
|
|
+ responds 204 (no leaks about whether the report was accepted or
|
|
|
+ ignored). Audit row shape: `action=CSP_VIOLATION,
|
|
|
+ entity_type=csp_violation, entity_id=NULL,
|
|
|
+ before_json=NULL, after_json=<inner report>, user_id=NULL,
|
|
|
+ user_email=NULL, ip_address=<client>, user_agent=<browser>`.
|
|
|
+ `AuditRepository::distinctEntityTypes()` already powers the
|
|
|
+ `/audit` view's filter dropdown, so `csp_violation` shows up
|
|
|
+ there automatically. `FatalErrorHandlerTest` CSP-line assertion
|
|
|
+ grew a `report-uri` check (drift fence). New
|
|
|
+ `tests/Controllers/CspReportControllerTest.php` (10 cases) pins
|
|
|
+ the 204-always rule, the body cap, the JSON-object-only contract,
|
|
|
+ the envelope unwrap, and the audit-row shape end-to-end against
|
|
|
+ an in-memory DB. Tests: 266 / 721 (was 252 / 683).
|
|
|
- **Where**: `public/index.php` lines 227-237.
|
|
|
- **What**: CSP is strict but silent — operators won't notice if a future
|
|
|
view inadvertently introduces an inline handler or new external host
|
|
|
@@ -935,7 +965,9 @@ A reasonable cadence (do not treat as binding):
|
|
|
17. ~~**R01-N17** (concurrent-tab OIDC state)~~ — accepted-by-design;
|
|
|
library uses fixed session keys, the realistic failure mode is a
|
|
|
one-line UX nit, see Status block.
|
|
|
-18. The rest as time permits.
|
|
|
+18. ~~**R01-N19** (CSP `report-uri` + audit endpoint)~~ — fixed in
|
|
|
+ `f59f368`.
|
|
|
+19. The rest as time permits.
|
|
|
|
|
|
Each fix should ship as its own commit per SPEC.md §14, with a follow-up
|
|
|
SPEC update if behaviour or config surface changes.
|