4.3 KiB
Integration & Tuning
This document complements the installation steps in docs/INSTALLATION.md by focusing on detector tuning, allowlists, and advanced integrations (log forwarding, Fail2Ban, etc.).
Example upload-logger.json (simplified) for UploadShield:
{
"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
ContentDetectorperforms 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— relaxeval()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.
- Add trusted URIs to
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, groupwww-data, mode0700. Files inside should be0600.
Fail2Ban integration (example)
Create a Fail2Ban filter that matches suspicious JSON log lines and captures the IP as <HOST>.
Filter (/etc/fail2ban/filter.d/php-upload.conf):
[Definition]
failregex = ^.*"event"\s*:\s*"suspicious".*"ip"\s*:\s*"(?P<host>\d{1,3}(?:\.\d{1,3}){3})".*$
ignoreregex =
Jail example (adjust logpath):
[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:
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.phpand.securityowned byrootand ensure logs and quarantine are not web-accessible.
For installation steps and per-site configuration, see docs/INSTALLATION.md.