Files
UploadShied/docs/INSTALLATION.md

176 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Installation & Production Deployment Guide
This guide shows a minimal, secure installation and rollout path for UploadShield's primary script (`upload-logger.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 `upload-logger.php` in a secure per-site folder (recommended `.security`).
2. Create `logs/`, `quarantine/`, `state/` and set strict ownership and permissions.
3. Configure `upload-logger.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 `upload-logger.php` is not web-accessible.
Example layout:
```
/var/www/sites/example-site/
├── public/
├── app/
├── uploads/
├── .security/
│ ├── upload-logger.php
│ └── logs/
│ └── uploads.log
├── quarantine/
└── state/
```
**3. Copy files & configure**
- Place `upload-logger.php` into `.security/upload-logger.php`.
- Copy `upload-logger.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/upload-logger-provision.yml` — Ansible playbook for bulk provisioning.
**5. PHPFPM configuration (per-site pool)**
Edit the site's FPM pool (example: `/etc/php/8.1/fpm/pool.d/example-site.conf`) and add:
```ini
; Ensure upload-logger runs before application code
php_admin_value[auto_prepend_file] = /var/www/sites/example-site/.security/upload-logger.php
```
Then reload PHP-FPM:
```bash
sudo systemctl reload php8.1-fpm
```
Notes:
- Use the absolute path to `upload-logger.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/upload-logger` 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.
Example quick test (on host):
```bash
# from site root
php -S 127.0.0.1:8000 -t . -d auto_prepend_file=/var/www/sites/example-site/.security/upload-logger.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 `upload-logger.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 `upload-logger.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 `upload-logger` files if needed.
**Further reading & files**
- Integration notes: [INTEGRATION.md](INTEGRATION.md)
- Provisioning script: `scripts/provision_dirs.sh`
- Ansible playbook: `scripts/ansible/upload-logger-provision.yml`
- Example configuration: `upload-logger.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.