Files
UploadShied/README.md
Gregor Klevze 037b176892 fix(scanner): avoid SVG/XML false positives; add allowlist and .gitignore
Relax payload scanner for XML/SVG by passing content-type into checks
Skip JS-style eval() detection when content-type is XML/SVG
Pass request Content-Type through sniff_file_for_php_payload() and raw-body checks
Add common XML/SVG content-types to allowlist.json
Add repository .gitignore (ignore logs, quarantine/, state/, env, vendor, IDE files)
2026-02-07 15:11:15 +01:00

4.1 KiB

Upload Logger (Hardened v3)

This repository contains the v3 upload-logging helper: a hardened single-file monitor that logs uploads, detects common evasion techniques, and optionally blocks suspicious uploads.

Primary file: upload-logger.php

Summary

  • Purpose: Log normal uploads and raw-body uploads, detect double-extension tricks, fake images, PHP payloads embedded in files, and provide flood detection.
  • Runs only for HTTP requests; recommended to enable via auto_prepend_file in a per-site PHP-FPM pool for broad coverage.

Key configuration (top of upload-logger.php)

  • $logFile — path to the log file (default: __DIR__ . '/logs/uploads.log').
  • $BLOCK_SUSPICIOUS — if true the script returns 403 and exits when suspicious uploads are detected.
  • $MAX_SIZE — threshold for WARN big_upload (default 50 MB).
  • $RAW_BODY_MIN — minimum raw request body size considered suspicious when $_FILES is empty (default 500 KB).
  • $FLOOD_WINDOW_SEC, $FLOOD_MAX_UPLOADS — lightweight per-IP flood detection window and max uploads before alerting.
  • $SNIFF_MAX_BYTES, $SNIFF_MAX_FILESIZE — parameters controlling fast content sniffing for PHP/webshell markers.
  • $LOG_USER_AGENT — include User-Agent in logs when true.

What it detects

  • Dangerous filenames (path-traversal, double extensions, hidden php-like dotfiles).
  • Fake images: file extension indicates an image but finfo returns a non-image MIME.
  • PHP/webshell markers inside file content (fast head-scan up to configured limits).
  • Archive uploads (.zip, .tar, etc.) flagged for attention.
  • Raw request bodies (e.g., application/octet-stream or streamed uploads) when $_FILES is empty and body size exceeds $RAW_BODY_MIN.
  • Flooding by counting uploads per-IP in a rolling window.

Logging and alerts

  • Each accepted upload generates an UPLOAD line with fields: ip, user, name, size, type, real (detected MIME), tmp, uri, and optional ua.
  • Suspicious uploads generate ALERT suspicious entries with reasons= listing detected flags (e.g., bad_name,fake_image,php_payload).
  • Other notes: WARN big_upload, NOTE archive_upload, MULTIPART_NO_FILES, and RAW_BODY are emitted when appropriate.

Integration notes

  • Preferred deployment: set php_admin_value[auto_prepend_file] in the site-specific PHP-FPM pool to the absolute path of upload-logger.php so it runs before application code.
  • If using sessions for user identification, the script safely reads $_SESSION['user_id'] only when a session is active; do not rely on it being present unless your app starts sessions earlier.
  • The script uses is_uploaded_file()/finfo where available; ensure the PHP fileinfo extension is enabled for best MIME detection.

Operational recommendations

  • Place the logs/ directory outside the webroot or deny web access to it.
  • Ensure correct owner/group and permissions (e.g., owner root, group www-data, chmod 750 on .security and chmod 640 for logs) and confirm PHP-FPM's user/group membership.
  • Rotate logs with logrotate (see INTEGRATION.md for an example snippet).
  • If your host uses SELinux/AppArmor, set correct contexts or adjust profiles so PHP-FPM can read the script and write logs.

Limitations & safety

  • This script improves visibility and blocks common upload tricks but cannot guarantee interception of every file-write vector (e.g., direct application writes, ZipArchive extraction, custom file APIs). Use it as part of a layered defense.
  • Content sniffing is limited to a head-scan to reduce CPU and false positives; tune $SNIFF_MAX_BYTES and $SNIFF_MAX_FILESIZE to balance coverage and performance.

Quick start

  1. Place upload-logger.php in a per-site secure folder (see INTEGRATION.md).
  2. Ensure the logs/ directory exists and is writable by PHP-FPM.
  3. Enable as an auto_prepend_file in the site pool and reload PHP-FPM.
  4. Monitor logs/uploads.log and adjust configuration options at the top of the script.

Support & changes

  • For changes, edit configuration variables at the top of upload-logger.php or adapt detection helpers as needed.

Generated for upload-logger.php (v3).