mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-11-09 19:20:09 +01:00
fix(security): make session-cookie hardening work under TLS termination
The passive scan flagged 3x MEDIUM 'PHPSESSID missing Secure' and an
admin-login cookie missing HttpOnly. Root cause was not the cookie code
but scheme detection: every call site read $_SERVER['HTTPS'] directly,
which is unset when TLS is terminated in front of PHP-FPM, so the Secure
flag was silently dropped.
Add RequestUtil::isSecure()/baseUrl() as the single scheme detector:
1. $_SERVER['HTTPS'] (direct TLS)
2. X-Forwarded-Proto — only from a loopback/private peer, so a remote
client cannot spoof it
3. SERVER_PORT == 443
Replace all 8 inline $_SERVER['HTTPS'] idioms (App, AdminAuth, 4x filepond
endpoints, validate-access, admin/acces, SystemController self-ping).
nginx: forward the scheme to php-fpm in all 4 fastcgi blocks
(fastcgi_param HTTPS $https + X-Forwarded-Proto $scheme) and uncomment
server_tokens off. Config validated with nginx -t (real config, alpine
container).
AdminAuth: logout() now clears the session cookie with the same
path/domain/secure/httponly/samesite it was set with, instead of the
legacy positional setcookie() that dropped SameSite.
Tests (+24, 340 total):
- RequestUtilTest: scheme detection incl. proxy trust boundaries
- SessionCookieTest: logout emits a hardened deletion cookie
- PeerTubeIntegrationTest: PeerTube keeps using its absolute instance_url
and is unaffected by scheme changes (Guzzle MockHandler)
- NginxConfigTest: pins HTTPS forwarding, HSTS includeSubDomains,
server_tokens off
PeerTube uses an absolute instance_url from the DB and never derives URLs
from the request, so the integration is unchanged — the regression tests
lock that invariant in.
This commit is contained in:
1 parent
e1f9cc9a9a
commit
554fc57455
17 files changed
+652
-29
No files matched your search
@@ -1,4 +1,4 @@
|
||||
Exported 80 tasks to /home/theophile/repos/xamxam/TODO.md
|
||||
Exported 81 tasks to /home/theophile/repos/xamxam/TODO.md
|
||||
rategy: run unusedSymbols report-only (10-14) first to get go/no-go reclaimable-byte data; per-page split (u-x) second, reusing template inventory in docs/css-split-analysis.md.
|
||||
|
||||
## In Progress
|
||||
@@ -6,14 +6,11 @@ rategy: run unusedSymbols report-only (10-14) first to get go/no-go reclaimable-
|
||||
## Pending
|
||||
- [ ] #test-env-deploy-code-chown-regression test-env deploy-code --chown regression documented in README --context test-env
|
||||
- [ ] #history-cleanup-66-commits [!medium] History cleanup: 66 commits squashed to 29 on top of main; pre-squash backup at refs/backup/pre-squash-tip (tree 8649514e) + git bundle /tmp/xamxam-presquash.bundle
|
||||
- [ ] #security-scan-passive-xamxam-erg-be [!high] Security scan (passive, xamxam.erg.be): verify nginx config drift — live HSTS is 'max-age=63072000; preload;' but repo nginx/xamxam.conf:58 has 'includeSubDomains; preload;'. Repo config is correct; deployed config is stale. Run 'just deploy-nginx' and re-check. --context security
|
||||
- [ ] #security-scan-scanner-s-cookie [!high] Security scan: scanner's 'Cookie PHPSESSID missing Secure' (3x MEDIUM). Code sets Secure conditionally via $_SERVER['HTTPS'] (App.php:29, AdminAuth.php:73, filepond). Likely scanner probed HTTP, or HTTPS var unset. Verify prod: nginx passes HTTPS/X-Forwarded-Proto to fastcgi so Secure flag is not silently dropped under TLS termination. --context security
|
||||
- [ ] #security-scan-admin-login [!high] Security scan: admin login cookie missing HttpOnly (scanner MEDIUM #3). AdminAuth::startSession sets httponly=true but login.php path may start session before AdminAuth hardening, or path=/admin scoping drops it. Trace session start order on /admin/login.php and ensure the login-response Set-Cookie carries HttpOnly+Secure+SameSite. --context security
|
||||
- [ ] #security-scan-low-reduce [!low] Security scan (LOW): reduce CSP script-src 'unsafe-inline'/'unsafe-eval' (nginx/xamxam.conf:59,148,193). Blockers documented: OverType editor init inline block + htmx Function() eval. Path: migrate inline init to external JS with nonce or hashes; check htmx version for CSP-safe build. Low priority (admin already auth-gated). --context security
|
||||
- [ ] #security-scan-low-server-tokens [!low] Security scan (LOW): server_tokens off is commented out (nginx/xamxam.conf:68) — live Server: nginx disclosure. Uncomment or set in http block; confirm token stripped. --context security
|
||||
- [ ] #security-scan-info-5 [!low] Security scan (INFO): 5 subdomains exist on shared hosts (www/ftp on 79.99.200.80, mail/wiki on 79.99.201.119, gitlab on 92.222.93.212). Session cookies are host-scoped (no Domain= set), so no cross-subdomain cookie leak — confirmed OK. Action: none unless a wildcard cert/Domain cookie is ever introduced. --context security
|
||||
- [ ] #security-scan-info-negative [!low] Security scan (INFO, negative result): certificate expiry check — live TLS cert expires 2026-12-02 (~49 days). Let's Encrypt auto-renew should cover it, but confirm certbot renew timer is active/enabled on server. --context deploy
|
||||
- [ ] #security-scan-meta-passive [!medium] Security scan meta: passive scan revealed repo nginx config != deployed nginx config (HSTS includeSubDomains + Referrer-Policy differ). Add a post-deploy drift check (e.g. curl live headers and diff against nginx/xamxam.conf expected values) so config drift is caught, not discovered by scanners. --context deploy
|
||||
- [ ] #deploy-the-security-scan-nginx [!high] Deploy the security-scan nginx fixes to production: run 'just deploy-nginx' then verify live headers (HSTS includeSubDomains, Server: without version, PHPSESSID Secure+HttpOnly+SameSite). Repo config is fixed; server is still running the stale config. --context deploy
|
||||
|
||||
## Completed
|
||||
- [x] #audit-all-docs-and [!high] Audit all docs/ and classify accurate vs stale
|
||||
@@ -78,6 +75,10 @@ rategy: run unusedSymbols report-only (10-14) first to get go/no-go reclaimable-
|
||||
- [x] #verify-final-tree-identical [!medium] Verify final tree identical to backup
|
||||
- [x] #decide-fate-of-stray [!low] Remove stray tracked commits.txt (6268-line git log dump) — Removed; no code references it
|
||||
- [x] #fix-6-pre-existing-phpstan [!medium] Fix 6 pre-existing phpstan errors (AdminAuth, ExportController x2, SystemController, TfeController, validate-file-fragment-shared)
|
||||
- [x] #security-scan-passive-xamxam-erg-be [!high] Security scan (passive, xamxam.erg.be): verify nginx config drift — live HSTS is 'max-age=63072000; preload;' but repo nginx/xamxam.conf:58 has 'includeSubDomains; preload;'. Repo config is correct; deployed config is stale. Run 'just deploy-nginx' and re-check. --context security
|
||||
- [x] #security-scan-scanner-s-cookie [!high] Security scan: scanner's 'Cookie PHPSESSID missing Secure' (3x MEDIUM). Code sets Secure conditionally via $_SERVER['HTTPS'] (App.php:29, AdminAuth.php:73, filepond). Likely scanner probed HTTP, or HTTPS var unset. Verify prod: nginx passes HTTPS/X-Forwarded-Proto to fastcgi so Secure flag is not silently dropped under TLS termination. --context security
|
||||
- [x] #security-scan-admin-login [!high] Security scan: admin login cookie missing HttpOnly (scanner MEDIUM #3). AdminAuth::startSession sets httponly=true but login.php path may start session before AdminAuth hardening, or path=/admin scoping drops it. Trace session start order on /admin/login.php and ensure the login-response Set-Cookie carries HttpOnly+Secure+SameSite. --context security
|
||||
- [x] #security-scan-low-server-tokens [!low] Security scan (LOW): server_tokens off is commented out (nginx/xamxam.conf:68) — live Server: nginx disclosure. Uncomment or set in http block; confirm token stripped. --context security
|
||||
|
||||
## Deferred / Blocked
|
||||
- [ ] #just-setup-backs-a [!medium] just setup backs a stale setup-dev.sh (clones php-live-reload, legacy admin/data/ dirs) — needs rewrite or removal
|
||||
|
||||
Reference in new issue
Block a user