Gregor Klevze aaaf59f178
Some checks failed
CI / build (8.0) (push) Has been cancelled
CI / build (8.1) (push) Has been cancelled
CI / build (8.2) (push) Has been cancelled
CI / build (8.3) (push) Has been cancelled
CI / build (8.4) (push) Has been cancelled
CI / PHP Lint & Basic Checks (matrix) (8.0) (push) Has been cancelled
CI / PHP Lint & Basic Checks (matrix) (8.1) (push) Has been cancelled
CI / PHP Lint & Basic Checks (matrix) (8.2) (push) Has been cancelled
Merge branch 'harden/quarantine-provisioning' into master
2026-02-12 14:51:57 +01:00

UploadShield (Hardened v3)

This repository contains UploadShield (formerly "Upload Logger"): a hardened PHP upload protection helper. It provides a single-file monitor that logs uploads, detects common evasion techniques, quarantines suspicious files, and can optionally block malicious uploads.

Primary file: uploadshield.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 uploadshield.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 uploadshield.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.
  • The script uses is_uploaded_file()/finfo where available; ensure the PHP fileinfo extension is enabled for best MIME detection.

Content detector & tuning

  • ContentDetector is now included and performs a fast head-scan of uploaded files to detect PHP open-tags and common webshell indicators (e.g., passthru(), system(), exec(), shell_exec(), proc_open(), popen(), base64_decode(), eval(), assert()).
  • The detector only scans the first N bytes of a file to limit CPU/io work; tune these limits in uploadshield.json:
    • limits.sniff_max_bytes — number of bytes to scan from file head (default 8192).
    • limits.sniff_max_filesize — only scan files up to this size in bytes (default 2097152 / 2MB).
  • Behavior note: eval() and similar tokens commonly appear inside SVG/JS contexts. The detector uses the detected MIME to be more permissive for XML/SVG-like content, but you should test and tune for your application's upload patterns to avoid false positives (see INTEGRATION.md). If your application legitimately accepts encoded or templated payloads, add application-specific allowlist rules (URI or content-type) in allowlist.json or extend uploadshield.json with detector-specific tuning before enabling blocking mode. Further integration
  • Read the INTEGRATION.md for detector tuning, allowlists, and examples for log forwarding and Fail2Ban.
  • See docs/INSTALLATION.md for a step-by-step per-site install and auto_prepend_file examples.
  • Provision the required directories (quarantine, state) and set ownership/SELinux via the included provisioning script: scripts/provision_dirs.sh.
  • Example automation: scripts/ansible/uploadshield-provision.yml and scripts/systemd/uploadshield-provision.service are included as examples to run provisioning at deploy-time or boot.

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 uploadshield.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 uploadshield.php or adapt detection helpers as needed.

Generated for uploadshield.php (UploadShield v3).

Additional documentation

Description
No description provided
Readme 96 KiB
Languages
PHP 89%
Shell 10.7%
PowerShell 0.3%