mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
- Consolidate 36 markdown files → 14 (plus TODO.md) - Merge overlapping docs into authoritative files: - database.md (from DATABASE_SPECIFICATION + QUICK_SCHEMA_REFERENCE + DATABASE_CONFIG + SETUP) - deployment.md (from SERVER_SETUP + COMPLETE_DEPLOYMENT_GUIDE + DEPLOYMENT_STEPS) - security.md (from SECURITY_ANALYSIS + TODO.SECURITY) - development.md (from DEVELOPMENT_GUIDE + LIVE_RELOAD_SETUP + TEST_CENTRALIZATION) - migration-history.md (from 11 past migration docs) - Standardise all filenames to lowercase - Remove non-doc files (Context.md research notes, chat export) - Remove superseded docs (SECURITY.md pre-SQLite, SECURITY_IMPLEMENTATION, README_SECURE_SEARCH) - Fix stale cross-references
83 lines
3.9 KiB
Markdown
83 lines
3.9 KiB
Markdown
# Security
|
||
|
||
Vulnerability analysis and resolution status for posterg-website.
|
||
|
||
> Based on security audit (2026-02-08). All items tracked below.
|
||
|
||
---
|
||
|
||
## Resolved
|
||
|
||
### Infrastructure / Deployment
|
||
|
||
| # | Issue | Severity | Resolution |
|
||
|---|-------|----------|------------|
|
||
| 1 | No HTTPS — admin credentials exposed in transit | 🔴 CRITICAL | TLS terminated upstream by reverse proxy. nginx.conf doesn't need to handle TLS directly. |
|
||
| 3 | Uploaded files stored inside webroot | 🟠 HIGH | Storage moved to `STORAGE_ROOT` (`/var/www/posterg/storage/`), defined in `config/bootstrap.php`. |
|
||
| 4 | File path mismatch — media broken & insecure | 🟠 HIGH | DB paths now storage-relative. New `public/media.php` serves files safely. `memoire.php` and `search.php` use `/media.php?path=…`. Cover recording fixed. |
|
||
| 5 | Rate limiter bypassed by IP spoofing (`X-Forwarded-For`) | 🟠 HIGH | `src/RateLimit.php` `getClientIdentifier()` uses `REMOTE_ADDR` only. |
|
||
| 6 | `.htaccess` rules silently ignored by nginx | 🟠 HIGH | All rules ported to `nginx/posterg.conf`. See `nginx/HTACCESS_TO_NGINX.md`. |
|
||
| 13 | Deprecated `X-XSS-Protection` header | 🔵 LOW | Removed from `nginx/posterg.conf`. |
|
||
|
||
### Frontend / Assets
|
||
|
||
| # | Issue | Severity | Resolution |
|
||
|---|-------|----------|------------|
|
||
| 10 | CDN stylesheet without SRI | 🟡 MEDIUM | CDN will not be used in production. Self-hosted, eliminating supply-chain risk. |
|
||
|
||
### Code Quality / Defence in Depth
|
||
|
||
| # | Issue | Severity | Resolution |
|
||
|---|-------|----------|------------|
|
||
| 14 | Missing `rel="noreferrer"` on external links | 🔵 LOW | `rel="noopener noreferrer"` applied in `public/admin/thanks.php`. |
|
||
| 15 | Unescaped integer outputs | 🔵 LOW | Explicit `(int)` casts added in `public/index.php` and `public/search.php`. |
|
||
| 16 | Redundant `DATABASE_PATH` constant | 🔵 LOW | Removed from `config/bootstrap.php`. |
|
||
|
||
### Admin Panel — Authentication & Sessions
|
||
|
||
| # | Issue | Severity | Resolution |
|
||
|---|-------|----------|------------|
|
||
| 2 | No PHP-level authentication in admin | 🔴 CRITICAL | `src/AdminAuth.php` implements session guard with `password_verify` + `session_regenerate_id`. All admin files call `AdminAuth::requireLogin()`. Credentials in gitignored `config/admin_credentials.php`. No-op when constant absent (dev/cli-server). |
|
||
| 8 | Session cookies not hardened | 🟡 MEDIUM | Resolved with #2. `AdminAuth::startSession()` sets `HttpOnly=true`, `SameSite=Strict`, `Secure=true` (off on cli-server), `Path=/admin`, `Lifetime=0`. |
|
||
|
||
---
|
||
|
||
## In Progress
|
||
|
||
| # | Issue | Severity | Status |
|
||
|---|-------|----------|--------|
|
||
| 7 | LIKE wildcard injection in admin search | 🟡 MEDIUM | Public `Database::searchTheses()` escapes `%` and `_` correctly. Same pattern must be applied to admin search and any other raw LIKE queries. |
|
||
|
||
---
|
||
|
||
## Not Yet Implemented
|
||
|
||
| # | Issue | Severity | Files |
|
||
|---|-------|----------|-------|
|
||
| 11 | Missing Content-Security-Policy on public pages | 🟡 MEDIUM | `nginx/posterg.conf` → add CSP header to main server block |
|
||
| 9 | `error.log` in web-accessible path | 🟡 MEDIUM | `public/admin/actions/formulaire.php` → use absolute path outside webroot |
|
||
| 12 | CSV import missing server-side MIME validation | 🟡 MEDIUM | `public/admin/import.php` → add `finfo` MIME check |
|
||
|
||
---
|
||
|
||
## Priority Order
|
||
|
||
1. ~~🔴 CRITICAL~~ — All done (items 1–2)
|
||
2. 🟡 **MEDIUM** — Items 7, 9, 11, 12 remaining
|
||
3. ~~🔵 LOW~~ — All done (items 13–16)
|
||
|
||
---
|
||
|
||
## Good Practices Already in Place
|
||
|
||
- ✅ SQL injection: all queries use PDO prepared statements
|
||
- ✅ XSS output: `htmlspecialchars()` on all user-controlled output
|
||
- ✅ CSRF: tokens with `bin2hex(random_bytes(32))`, validated with `hash_equals()`
|
||
- ✅ File upload: MIME type validated with `finfo`
|
||
- ✅ Input validation: year, IDs, pagination cast to integers
|
||
- ✅ LIKE wildcard escaping in public search (`Database::escapeLikeString`)
|
||
|
||
---
|
||
|
||
*Last updated: 2026-02-08*
|