mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 01:53:03 +02:00
3.8 KiB
3.8 KiB
Security
Current security posture for XAMXAM.
This supersedes the earlier
security.md(2026-02-08 audit). The original 16-item audit is closed; the items below reflect the current state.
Authentication — admin
- PHP session auth:
app/src/AdminAuth.php. Password-only (no username). Credentials previously in a gitignored PHP file; the current build stores the bcrypt hash insite_settings.admin_password_hash(manageable from/admin/account). AdminAuth::requireLogin()guards every admin action/route.- Session cookies hardened:
HttpOnly,SameSite=Strict,Secure,Path=/admin; regenerated on login. - nginx
auth_basiclayer has been removed; the PHP session layer is the only gate. (LDAP-based login is a proposed future enhancement — seeLDAP_AUTH_PLAN.md/LDAP_SPEC.md. It is not implemented.)
Transport & headers
Enforced in nginx/xamxam.conf (see nginx/docs/SECURITY_HEADERS.md):
- HSTS (
Strict-Transport-Security, 730 days, preload) - CSP —
default-src 'self'; … frame-ancestors 'none'on public pages;frame-ancestors 'self'where the app embeds allowed content; admin CSP includesscript-src 'unsafe-inline'for the OverType editor.object-src 'none'. X-Frame-Options: DENY(clickjacking)X-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originPermissions-Policy(geo/mic/camera disabled)Cross-Origin-Opener-Policy/Cross-Origin-Resource-Policy: same-originX-Robots-Tag: noindex, nofollowon/admin/
X-XSS-Protection is intentionally omitted (deprecated; see
nginx/docs/SECURITY_HEADERS.md for rationale).
Rate limiting
Defined in the nginx config limit_req_zone and enforced by
app/src/RateLimit.php:
- General requests:
30 r/m - Search endpoint:
30 r/m - Admin panel:
300 r/m(burst 30)
The PHP limiter uses REMOTE_ADDR only (not X-Forwarded-For) to avoid IP
spoofing.
Files & storage
- Uploads live outside the webroot under
app/storage/(tfe/,theses/), served on demand viaMediaController/FileAccessControllerthrough controlled endpoints (/media), not direct static access. - nginx blocks
/storage,/src,/templates, DB/sql/env/md files, and hidden files. The DocumentRoot isapp/public/only. - Restricted-file downloads are gated by a request/approval/token flow
(
file_access_*tables). - Logs write to
app/storage/logs/— outside the webroot, not publicly served.
Injection & output
- SQL: all queries use PDO prepared statements.
- LIKE wildcards:
Database::escapeLikeString()escapes%and_(public search and related queries). - XSS:
htmlspecialchars()on all user-controlled output; integer/ID inputs cast. - CSRF: per-session tokens (
bin2hex(random_bytes(32))), compared withhash_equals(). - File uploads: MIME validated (
finfo); FilePond prevalidation + server-side checks inFilepondHandler. - Markdown/HTML: user content (pages, help blocks) rendered via
league/commonmark; HTML in admin-editable content is expected.
Defence in depth / misc
- External links use
rel="noopener noreferrer". - Decryption/
Cryptofailures are logged without leaking secrets; SMTP password is stored encrypted insmtp_settingsand rotated viajust reencrypt-password. - Admin operations are recorded in
admin_audit_log(resource, action, status, IP, User-Agent).
Areas to keep monitored
- Tightening the public CSP (
frame-ancestors 'none'vs'self'on embed routes) is an active topic — seeTODO.md. - Sensitive file downloads and their expiry/token handling are worth periodic review as usage grows.
See also: nginx/docs/SECURITY_HEADERS.md, nginx/docs/PHP_AUTH_LAYER.md,
nginx/docs/PRODUCTION_DEPLOYMENT.md.