Add Turnstile protection and harden export workflow
This commit is contained in:
@@ -1,2 +1,104 @@
|
||||
# Zefix_search
|
||||
# Silias ZEFIX Export
|
||||
|
||||
Ein PHP-Dienst, der ZEFIX-Suchaufträge asynchron verarbeitet und den fertigen CSV-Export über einen zeitlich begrenzten Download-Link zustellt.
|
||||
|
||||
Vorausgesetzt werden PHP 8.1 oder neuer, die Erweiterungen cURL und JSON sowie ein korrekt konfigurierter CA-Zertifikatsspeicher für die TLS-Prüfung von Cloudflare, ZEFIX und SMTP.
|
||||
|
||||
## Missbrauchsschutz
|
||||
|
||||
Der Export ist standardmässig **fail-closed**: Ohne vollständig konfigurierte Cloudflare-Turnstile-Schlüssel bleibt der Absende-Button deaktiviert und `submit.php` nimmt keine Aufträge an.
|
||||
|
||||
Aktivierte Schutzschichten:
|
||||
|
||||
- Cloudflare Turnstile im Managed-Modus, inklusive serverseitiger Siteverify-Prüfung
|
||||
- Hostname- und Action-Prüfung für Turnstile-Tokens
|
||||
- signierte Formularzeit und Honeypot-Feld ohne Session-Cookie
|
||||
- Rate-Limits pro IP-Adresse und E-Mail-Adresse
|
||||
- harte Grenzen für Orte, Rechtsformen, resultierende API-Aufrufe und Queue-Grösse
|
||||
- Deduplizierung identischer offener Aufträge
|
||||
- private Speicherung von Auftragsdaten und Exportdateien ausserhalb des Webroots
|
||||
- 128-Bit-Download-Token und automatische Ablaufzeit
|
||||
- CLI-Sperre für Executor, Cleanup und administratives Löschen
|
||||
- eintägiger Cache für Gemeinden und Rechtsformen
|
||||
|
||||
## Erforderliche Umgebungsvariablen
|
||||
|
||||
| Variable | Bedeutung |
|
||||
| --- | --- |
|
||||
| `TURNSTILE_SECRET` | Geheimer Schlüssel des bestehenden Turnstile-Widgets für Siteverify |
|
||||
| `APP_SECRET` | Zufälliger geheimer Wert für Formulartoken und pseudonymisierte Rate-Limits |
|
||||
| `ZEFIX_PRIVATE_DIR` | Absoluter, dauerhaft beschreibbarer Pfad **ausserhalb** des Webroots |
|
||||
| `username` | Benutzername der ZEFIX-API |
|
||||
| `password` | Passwort der ZEFIX-API |
|
||||
| `smtppassword` | Passwort des SMTP-Kontos |
|
||||
|
||||
Verwendet wird ausschliesslich das bestehende Turnstile-Widget `Zefix` mit dem Sitekey `0x4AAAAAAD7CJrWpNiK0-A7h`. Es darf nicht neu erstellt oder rotiert werden. Das Widget muss im Cloudflare-Dashboard als **Managed** mit dem Hostnamen `zefix.silias.ch` konfiguriert sein; Pre-Clearance bleibt deaktiviert. Das Secret gehört ausschliesslich als `TURNSTILE_SECRET` in die Serverumgebung und niemals ins Repository.
|
||||
|
||||
Empfohlene Werte:
|
||||
|
||||
```text
|
||||
TURNSTILE_ALLOWED_HOSTNAME=zefix.silias.ch
|
||||
PUBLIC_BASE_URL=https://zefix.silias.ch
|
||||
ZEFIX_PRIVATE_DIR=/var/lib/zefix-export
|
||||
APP_SECRET=<mindestens 32 zufällige Bytes>
|
||||
```
|
||||
|
||||
Das bisherige, nicht versionierte `env_vars.php` wird für eine schonende Migration weiterhin geladen. Neue Installationen sollten echte Prozess-/PHP-FPM-Umgebungsvariablen verwenden.
|
||||
|
||||
## Optionale Konfiguration
|
||||
|
||||
| Variable | Standard | Bedeutung |
|
||||
| --- | ---: | --- |
|
||||
| `RATE_LIMIT_IP_MAX` | `3` | Aufträge pro IP-Zeitfenster |
|
||||
| `RATE_LIMIT_IP_WINDOW_SECONDS` | `900` | IP-Zeitfenster |
|
||||
| `RATE_LIMIT_EMAIL_MAX` | `5` | Aufträge pro E-Mail-Zeitfenster |
|
||||
| `RATE_LIMIT_EMAIL_WINDOW_SECONDS` | `86400` | E-Mail-Zeitfenster |
|
||||
| `MAX_SEATS_PER_JOB` | `500` | maximale Orte pro Auftrag |
|
||||
| `MAX_LEGAL_FORMS_PER_JOB` | `50` | maximale Rechtsformen pro Auftrag |
|
||||
| `MAX_REQUESTS_PER_JOB` | `5000` | maximales Produkt aus Orten × Rechtsformen |
|
||||
| `MAX_QUEUE_SIZE` | `20` | maximale offene Aufträge |
|
||||
| `DOWNLOAD_RETENTION_HOURS` | `48` | Gültigkeit fertiger Exporte |
|
||||
| `STALE_TASK_RETENTION_HOURS` | `168` | maximale Lebensdauer offener Aufträge |
|
||||
| `REFERENCE_CACHE_SECONDS` | `86400` | Cache für Gemeinden und Rechtsformen |
|
||||
| `TRUSTED_PROXY_IPS` | leer | kommaseparierte IPs eigener Reverse-Proxies |
|
||||
| `EXPORT_BCC_EMAIL` | leer | optionale BCC-Adresse; standardmässig kein BCC |
|
||||
| `APP_ENV` | leer | nur lokal auf `development` setzen; erlaubt die offiziellen Turnstile-Testschlüssel auf Loopback |
|
||||
| `SMTP_HOST` | `mxe98c.netcup.net` | SMTP-Server |
|
||||
| `SMTP_USERNAME` | `info@silias.ch` | SMTP-Benutzer |
|
||||
| `SMTP_SECURE` | `ssl` | SMTP-Verschlüsselung |
|
||||
| `SMTP_PORT` | `465` | SMTP-Port |
|
||||
|
||||
`TRUSTED_PROXY_IPS` darf nur tatsächlich kontrollierte Proxy-Adressen enthalten. Ohne Eintrag werden vom Browser gelieferte `X-Forwarded-For`- oder `CF-Connecting-IP`-Header bewusst ignoriert.
|
||||
|
||||
## Cronjob
|
||||
|
||||
`cronjobs.sh` führt zuerst die automatische Bereinigung und danach den Task-Executor aus. Beide PHP-Skripte akzeptieren ausschliesslich CLI-Aufrufe.
|
||||
|
||||
Beispiel:
|
||||
|
||||
```cron
|
||||
*/2 * * * * /absoluter/pfad/cronjobs.sh
|
||||
```
|
||||
|
||||
Ein manueller Cleanup kann mit `php cleanup.php` gestartet werden. Alle offenen Aufträge werden nur nach ausdrücklicher Bestätigung gelöscht:
|
||||
|
||||
```bash
|
||||
php deleteFiles.php --confirm
|
||||
```
|
||||
|
||||
## Nginx-Härtung
|
||||
|
||||
Die PHP-Skripte sperren Webzugriffe selbst. Zusätzlich sollten Altpfade und Wartungsskripte bereits in Nginx blockiert werden:
|
||||
|
||||
```nginx
|
||||
location ~ ^/(taskExecuter|cleanup|deleteFiles)\.php$ { return 404; }
|
||||
location ^~ /tasks/ { return 404; }
|
||||
location ^~ /download/ { return 404; }
|
||||
location = /env_vars.php { return 404; }
|
||||
```
|
||||
|
||||
Nach dem ersten CLI-Lauf werden alte JSON-Aufträge aus `tasks/` in den privaten Speicher migriert. Anschliessend sollten die alten öffentlichen Verzeichnisse `tasks/` und `download/` nach Kontrolle entfernt werden.
|
||||
|
||||
## Datenschutz
|
||||
|
||||
Die öffentliche Datenschutzerklärung liegt unter `datenschutz.php`. Sie beschreibt Turnstile, die verarbeiteten Daten und die implementierten Löschfristen. Wenn später Analyse-, Marketing- oder weitere Drittanbieter-Dienste ergänzt werden, müssen Text und gegebenenfalls die Einwilligungsverwaltung erneut geprüft werden.
|
||||
|
||||
Reference in New Issue
Block a user