# 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= ``` Das bisherige, nicht versionierte `env_vars.php` wird für eine schonende Migration weiterhin geladen. Neue Installationen sollten echte Prozess-/PHP-FPM-Umgebungsvariablen verwenden. Eine vollständige Vorlage ohne echte Zugangsdaten liegt in [`.env.example`](.env.example). Für eine klassische Installation kann sie als `.env` **einen Ordner über dem Projektverzeichnis** abgelegt werden. Diese Datei wird beim Start automatisch geladen. Bereits gesetzte Prozessvariablen und Werte aus der bisherigen `env_vars.php` haben Vorrang. Beispiel bei einem Projekt unter `/var/www/zefix`: ```text /var/www/.env # echte, nicht versionierte Zugangsdaten /var/www/zefix/app.php # Projekt ``` Alternativ kann die Vorlage weiterhin für ein Deployment-Panel, Docker Compose (`env_file`) oder die PHP-FPM-Konfiguration verwendet werden. ## 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.