176 lines
7.3 KiB
Markdown
176 lines
7.3 KiB
Markdown
# Installation & Production Deployment Guide
|
||
|
||
This guide shows a minimal, secure installation and rollout path for UploadShield's primary script (`uploadshield.php`).
|
||
Follow these steps in a staging environment first; do not enable blocking until detectors are tuned.
|
||
|
||
**Prerequisites**
|
||
- A Linux host running PHP-FPM (PHP 8.0+ recommended).
|
||
- `composer` available for dev tasks.
|
||
- SSH/privileged access to configure the site pool and run provisioning scripts.
|
||
|
||
**Quick overview**
|
||
1. Place `uploadshield.php` in a secure per-site folder (recommended `.security`).
|
||
2. Create `logs/`, `quarantine/`, `state/` and set strict ownership and permissions.
|
||
3. Configure `uploadshield.json` for your environment; keep `ops.block_suspicious` off for initial tuning.
|
||
4. Enable `auto_prepend_file` in the site PHP-FPM pool to run the logger before application code.
|
||
5. Verify logging, tune detectors, deploy log rotation, and enable alerting.
|
||
|
||
**1. Clone & dependencies (developer workstation)**
|
||
- Clone the repository and install dev deps (for tests/static analysis):
|
||
|
||
```bash
|
||
git clone <repo-url> /srv/uploadshield
|
||
cd /srv/uploadshield
|
||
composer install --no-interaction --prefer-dist
|
||
```
|
||
|
||
Run tests locally:
|
||
```bash
|
||
vendor/bin/phpunit --configuration phpunit.xml
|
||
vendor/bin/phpstan analyse -c phpstan.neon
|
||
```
|
||
|
||
**2. Recommended file layout (per-site)**
|
||
Use a hidden per-site security folder so `uploadshield.php` is not web-accessible.
|
||
|
||
Example layout:
|
||
|
||
```
|
||
/var/www/sites/example-site/
|
||
├── public/
|
||
├── app/
|
||
├── uploads/
|
||
├── .security/
|
||
│ ├── uploadshield.php
|
||
│ └── logs/
|
||
│ └── uploads.log
|
||
├── quarantine/
|
||
└── state/
|
||
Place `uploadshield.php` into `.security/uploadshield.php`.
|
||
|
||
**3. Copy files & configure**
|
||
- Place `uploadshield.php` into `.security/uploadshield.php`.
|
||
- Copy `uploadshield.json` from the repository to the same directory and edit paths to absolute values, e.g.:
|
||
- `paths.log_file` → `/var/www/sites/example-site/.security/logs/uploads.log`
|
||
- `paths.quarantine_dir` → `/var/www/sites/example-site/quarantine`
|
||
- `paths.state_dir` → `/var/www/sites/example-site/state`
|
||
- Ensure `ops.block_suspicious` is `false` initially (observe mode).
|
||
|
||
**4. Create directories & set permissions (run as root)**
|
||
Adjust user/group to your site environment (`www-data` used in examples):
|
||
|
||
```bash
|
||
# example: run on target host as root
|
||
mkdir -p /var/www/sites/example-site/.security/logs
|
||
mkdir -p /var/www/sites/example-site/quarantine
|
||
mkdir -p /var/www/sites/example-site/state
|
||
chown -R root:www-data /var/www/sites/example-site/.security
|
||
chmod 750 /var/www/sites/example-site/.security
|
||
chmod 750 /var/www/sites/example-site/.security/logs
|
||
# quarantine must be restrictive
|
||
chown -R root:www-data /var/www/sites/example-site/quarantine
|
||
chmod 0700 /var/www/sites/example-site/quarantine
|
||
# state directory writable by PHP-FPM if required (group-write)
|
||
chown -R root:www-data /var/www/sites/example-site/state
|
||
chmod 0750 /var/www/sites/example-site/state
|
||
# ensure log file exists with safe perms
|
||
touch /var/www/sites/example-site/.security/logs/uploads.log
|
||
chown root:www-data /var/www/sites/example-site/.security/logs/uploads.log
|
||
chmod 0640 /var/www/sites/example-site/.security/logs/uploads.log
|
||
```
|
||
|
||
Alternatively use the included provisioning scripts on the host:
|
||
- `scripts/provision_dirs.sh` — run as root; idempotent and attempts to set SELinux fcontext.
|
||
- `scripts/ansible/uploadshield-provision.yml` — Ansible playbook for bulk provisioning.
|
||
|
||
**5. PHP‑FPM configuration (per-site pool)**
|
||
Edit the site's FPM pool (example: `/etc/php/8.1/fpm/pool.d/example-site.conf`) and add:
|
||
php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/uploadshield.php
|
||
```ini
|
||
; Ensure uploadshield runs before application code
|
||
php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/uploadshield.php
|
||
```
|
||
|
||
Then reload PHP-FPM:
|
||
|
||
```bash
|
||
sudo systemctl reload php8.1-fpm
|
||
```
|
||
|
||
Notes:
|
||
- Use the absolute path to `uploadshield.php`.
|
||
- If your host uses a shared PHP-FPM pool, consider enabling per-vhost `auto_prepend_file` via nginx/apache or create a dedicated pool for the site.
|
||
|
||
**6. Log rotation**
|
||
Create `/etc/logrotate.d/uploadshield` with content adapted to your paths:
|
||
|
||
```
|
||
/var/www/sites/example-site/.security/logs/uploads.log {
|
||
rotate 7
|
||
size 10M
|
||
compress
|
||
missingok
|
||
notifempty
|
||
copytruncate
|
||
create 0640 root www-data
|
||
sharedscripts
|
||
postrotate
|
||
if systemctl is-active --quiet php8.1-fpm; then
|
||
systemctl reload php8.1-fpm >/dev/null 2>&1 || true
|
||
fi
|
||
endscript
|
||
}
|
||
```
|
||
|
||
`copytruncate` is safe and avoids needing to stop PHP; alternatively use `postrotate` to reload FPM.
|
||
|
||
**7. Verify installation (smoke tests)**
|
||
- Upload a benign file via your app or via a simple test form and confirm a JSON `upload` line appears in the log.
|
||
- Upload a file containing `<?php` to confirm detectors log `suspicious_upload` entries.
|
||
- Check `logs/uploads.log` for events.
|
||
|
||
php -S 127.0.0.1:8000 -t . -d auto_prepend_file=/var/www/sites/example-site/.security/uploadshield.php
|
||
```bash
|
||
# from site root
|
||
php -S 127.0.0.1:8000 -t . -d auto_prepend_file=/var/www/sites/example-site/.security/uploadshield.php
|
||
# then curl a file POST to your test endpoint
|
||
curl -F "file=@/path/to/sample.txt" http://127.0.0.1:8000/upload_test.php
|
||
```
|
||
|
||
**8. Tuning & staging**
|
||
- Keep `ops.block_suspicious` set to `false` while monitoring logs and tuning:
|
||
- `allowlists.base64_uris` — add URIs for trusted base64 endpoints.
|
||
- `allowlists.ctypes` — add trusted content-types such as `image/svg+xml` if needed.
|
||
- `limits.sniff_max_bytes` / `limits.sniff_max_filesize` — tune scanning cost vs coverage.
|
||
- Run the system under representative traffic and check for false positives.
|
||
|
||
**9. Gradual enable blocking**
|
||
- After tuning, enable blocking in a controlled manner:
|
||
1. Set `ops.block_suspicious` → `true` in `uploadshield.json` on a small subset of sites or a canary host.
|
||
2. Monitor errors, rollback quickly if issues appear.
|
||
3. Gradually roll out to remaining hosts.
|
||
|
||
**10. Monitoring & alerting**
|
||
- Forward `logs/uploads.log` to your SIEM or log aggregator (Filebeat/Fluentd).
|
||
- Create alerts for `event == suspicious_upload` or `event == raw_body` and for rapid flood counts.
|
||
- Monitor disk usage for `logs/` and ensure `logrotate` is active.
|
||
|
||
**11. Security & operational checklist**
|
||
- Ensure `quarantine/` and `.security/logs` are not accessible from the web server.
|
||
- Verify SELinux/AppArmor contexts after running provisioning.
|
||
- Ensure owner/group are set to root and web group (e.g., `root:www-data`) and modes match the guide.
|
||
Keep `uploadshield.php` readable by root (644) and the logs readable only by the intended group (640).
|
||
|
||
**Rollback**
|
||
- Disable `php_admin_value[auto_prepend_file]` in the pool and reload PHP-FPM.
|
||
- Remove or rotate the `uploadshield` files if needed.
|
||
|
||
**Further reading & files**
|
||
- Integration notes: [INTEGRATION.md](INTEGRATION.md)
|
||
- Provisioning script: `scripts/provision_dirs.sh`
|
||
- Ansible playbook: `scripts/ansible/uploadshield-provision.yml`
|
||
- Example configuration: `uploadshield.json`
|
||
|
||
---
|
||
If you want, I can: (a) generate a site-specific copy of these snippets for your exact paths/PHP version, (b) open a PR with the updated documentation, or (c) produce a one-command installer playbook that runs the provisioning and copies files to a remote host. Tell me which option you prefer.
|