# 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](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 - Auto-merge & Dependabot: [docs/auto-merge.md](docs/auto-merge.md)