## Integration & Tuning This document complements the installation steps in [docs/INSTALLATION.md](docs/INSTALLATION.md) by focusing on detector tuning, allowlists, and advanced integrations (log forwarding, Fail2Ban, etc.). Example `upload-logger.json` (simplified): ```json { "modules": { "flood": true, "filename": true, "mime_sniff": true, "hashing": true, "base64_detection": true, "raw_peek": false, "archive_inspect": true, "quarantine": true }, "paths": { "log_file": "logs/uploads.log", "quarantine_dir": "quarantine", "state_dir": "state", "allowlist_file": "allowlist.json" }, "limits": { "max_size": 52428800, "raw_body_min": 512000, "sniff_max_bytes": 8192, "sniff_max_filesize": 2097152 }, "ops": { "quarantine_owner": "root", "quarantine_group": "www-data", "quarantine_dir_perms": "0700", "block_suspicious": false }, "allowlists": { "base64_uris": [ "/api/uploads/avatars", "#/hooks/(github|gitlab|stripe|slack)#" ], "ctypes": ["image/svg+xml","application/xml","text/xml"] } } ``` Notes: - Remove the `//` comments if copying from examples. Use absolute paths in production where possible. ### Content detector tuning - The `ContentDetector` performs a fast head-scan to detect PHP open-tags and common webshell indicators (e.g., `passthru`, `system`, `exec`, `base64_decode`, `eval`, `assert`). - Tuning options (in `upload-logger.json`): - `limits.sniff_max_bytes` (default 8192) — how many bytes to scan from the file head. - `limits.sniff_max_filesize` (default 2097152) — only scan files up to this size. - `detectors.content.allow_xml_eval` — relax `eval()` detection for XML/SVG when appropriate. False positives - `eval(` appears in benign contexts (SVG/JS). To reduce false positives: - Add trusted URIs to `allowlists.base64_uris`. - Add trusted content-types to `allowlists.ctypes`. - Tune scan size limits. ### Allowlists - `allowlists.base64_uris`: URI patterns (substring or PCRE when wrapped with `#`) that should bypass base64/raw detection. - `allowlists.ctypes`: content-types to treat as permitted for encoded payloads (e.g., `image/svg+xml`). ### Archive inspection & quarantine - Archives uploaded are flagged and—if quarantine is enabled—moved to the quarantine directory for inspection. - Quarantine should be owner `root`, group `www-data`, mode `0700`. Files inside should be `0600`. ## Fail2Ban integration (example) Create a Fail2Ban filter that matches suspicious JSON log lines and captures the IP as ``. Filter (`/etc/fail2ban/filter.d/php-upload.conf`): ```ini [Definition] failregex = ^.*"event"\s*:\s*"suspicious".*"ip"\s*:\s*"(?P\d{1,3}(?:\.\d{1,3}){3})".*$ ignoreregex = ``` Jail example (adjust `logpath`): ```ini [php-upload] enabled = true filter = php-upload logpath = /var/www/sites/*/.security/logs/uploads.log maxretry = 3 findtime = 600 bantime = 86400 action = nftables[name=php-upload, port="http,https", protocol=tcp] ``` Test with `fail2ban-regex` using a representative JSON log line. ## Central log aggregation (Filebeat / rsyslog) Forward JSON logs to your aggregator to centralize alerts and analysis. Example Filebeat input: ```yaml filebeat.inputs: - type: log paths: - /var/www/sites/*/.security/logs/uploads.log json.keys_under_root: true json.add_error_key: true fields: source: php-upload-logger output.logstash: hosts: ["logserver:5044"] ``` ## Logrotate & SELinux notes Per-site `logrotate` snippets are included in `examples/logrotate.d/upload-logger`. Use `copytruncate` or reload PHP-FPM after rotation. If SELinux is enabled, the provisioning script attempts to register fcontexts and run `restorecon`. Verify contexts manually as needed. ## Final notes - Use observe mode (`ops.block_suspicious: false`) while tuning. - After tuning, enable blocking in a controlled rollout (canary hosts first). - Keep `upload-logger.php` and `.security` owned by `root` and ensure logs and quarantine are not web-accessible. For installation steps and per-site configuration, see `docs/INSTALLATION.md`.