Dieses Update schließt eine Sicherheitslücke im REST-Proxy von benno-web (FS#1506, FS#1507, FS#1508). Über
https://<server>/benno/rest.php sieht jedes Konto jetzt genau die Mails, die es auch in der Weboberfläche sieht.
Das gilt auch für den Abruf einzelner Mails und Anhänge.
Einordnung der Lücke:
rest.php. Die Weboberfläche war nicht betroffen. Dort zeigt benno-web nur Mails aus der eigenen, gefilterten Trefferliste an; eine fremde Mail lässt sich darüber nicht aufrufen. Permalinks waren ebenfalls nicht betroffen. Der Pfad musste ebenso über das Internet erreichbar sein.rest.php mit HTTP 401.rest.php auch Mails abrufen, die sein Adressfilter ausschließt, innerhalb der Container, die seinem Konto zugewiesen sind.| Zugriff | Änderung nötig? |
|---|---|
| Weboberfläche, Permalinks | Nein |
benno-client und Skripte, die direkt gegen benno-rest gehen (Port 21080, Shared Secret aus rest.conf) | Nein |
Eigene Skripte, Fremdsysteme und Integrationen, die https://<server>/benno/rest.php/... aufrufen | Ja, prüfen (Abschnitte 2–6) |
Kopano-WebApp-Plugin (bennopath = .../benno/rest.php) | Nach dem Update testen (Abschnitt 7) |
| Docker-Appliance | Fix ab Version 2.10.11 enthalten |
Der Fix besteht aus zwei Teilen: benno-web übergibt den Benutzerfilter, benno-rest setzt ihn beim Mailabruf durch. Wer nur eines der beiden Pakete aktualisiert, ist nicht geschützt.
Vorher
benno-web 2.10.10, benno-rest 2.10.8 (oder älter)
Nachher
apt-get update apt-get install benno-web benno-rest dpkg -l benno-web benno-rest # erwartet: 2.10.11 bzw. 2.10.9 (oder neuer)
Das Paket benno-rest startet den Dienst benno-rest selbst neu.
Docker-Appliance: Der Fix ist ab Version 2.10.11 der Appliance enthalten.
Über rest.php sind nur noch diese Endpunkte erreichbar:
| Endpunkt | Zweck |
|---|---|
/search | Suche |
/kopano | Suche für das Kopano-Plugin |
/mail | einzelne Mail abrufen |
/attachment | Anhang abrufen |
/logout | Sitzung beenden |
Alle anderen Endpunkte antworten für jede Rolle, auch für ADMIN, mit HTTP 403.
Vorher (Lizenzabfrage über den Proxy)
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/license?archive=BennoContainer' # HTTP 200, Lizenzdaten
Nachher
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/license?archive=BennoContainer' # HTTP 403
Stattdessen direkt gegen benno-rest gehen. Adresse, Benutzer und Secret stehen in /etc/benno-web/rest.conf
(BASE_URL, REST_USER, SHARED_SECRET; fehlen die ersten beiden, gelten http://localhost:21080 und
benno2):
curl -u benno2:<SHARED_SECRET> 'http://localhost:21080/license' # HTTP 200, Lizenzdaten als JSON
Lauscht benno-rest nur auf 127.0.0.1:21080, geht der direkte Aufruf nur vom Server selbst aus. Von einem anderen
Rechner aus ist benno-rest nur erreichbar, wenn es auf einer Netzwerkadresse lauscht.
Docker-Appliance: benno-rest lauscht im Container nur auf 127.0.0.1:21080. Der docker run-Aufruf der
Appliance veröffentlicht nur die Ports 22, 80 und 22500, Port 21080 also nicht. Der direkte Aufruf geht deshalb nur im
Container. Dort ist kein curl installiert, aber wget. Das Secret steht in /etc/benno-web/rest.conf, dem
eingebundenen Volume /etc/benno-web:
docker exec bma wget -qO- --user=benno2 --password='<SHARED_SECRET>' http://localhost:21080/license # Lizenzdaten als JSON
Das Shared Secret hat Vollzugriff auf alle Container. Es gehört nicht in Skripte auf Arbeitsplatzrechnern.
rest.php wendet jetzt bei jedem Endpunkt den Filter des angemeldeten Kontos an, auch bei /mail und
/attachment. Eine Mail außerhalb des Filters beantwortet benno-rest mit HTTP 404, also wie eine unbekannte ID.
Welche Mails ein Konto sieht, hängt von der Rolle ab:
| Rolle | Sichtbare Mails über rest.php | Eigener filterQuery-Parameter |
|---|---|---|
| USER, USERADMIN | Mails zu den eigenen Adressen, eingeschränkt durch die globalen und die eigenen Filter. Alle Filter gelten; vorher galt nur der letzte. | wird ignoriert |
| REVISOR | alle Mails der zugewiesenen Container | wird ignoriert |
| ADMIN | wie USER, also die eigenen Adressen und Filter | erlaubt, z. B. filterQuery=* für alle Mails |
| SITEADMIN | wie USER | wird ignoriert |
Konto ohne Adresse und ohne Filter (auch ADMIN ohne filterQuery) | keine (0 Treffer, /mail 404) | – |
Ein Integrationskonto, das auf alle Mails zugreifen soll, braucht deshalb eine dieser Konfigurationen:
filterQuery=* mitschicken. Ohne den Parameter gilt der eigene Filter.*@* am Konto, bei jeder Rolle. Der daraus erzeugte Filter trifft jede Mail mit Absender oder Empfänger.
Vorher (Konto api mit Rolle USER und einer Adresse holt eine beliebige Mail per ID)
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/mail' \ -d archive=BennoContainer -d id=2026:8B708B8C8A5C331... # HTTP 200, auch wenn die Mail nicht zur Adresse von api gehört
Nachher
# dasselbe Konto: HTTP 404, die Mail liegt außerhalb seines Filters # Variante 1: Konto auf REVISOR umstellen benno-useradmin -u api -r REVISOR # Variante 2: Konto mit Rolle ADMIN, Filter ausdrücklich mitschicken curl -u api-admin:Passwort 'https://benno.example.com/benno/rest.php/mail' \ -d archive=BennoContainer -d id=2026:8B708B8C8A5C331... -d 'filterQuery=*' # HTTP 200
Ein Konto mit Rolle ADMIN ohne Adresse, das bisher kein filterQuery mitgeschickt hat, findet nach dem Update
nichts mehr. In diesem Fall Variante 1 oder Variante 2 umsetzen.
rest.php leitet je Endpunkt nur die Parameter weiter, die benno-rest dort auswertet. Alle anderen fallen ohne
Fehlermeldung weg. GET- und POST-Parameter funktionieren beide weiterhin.
| Endpunkt | Weitergeleitete Parameter |
|---|---|
/search, /kopano | query, full, sort, sortAsc, start, limit |
/mail | id, format, header, skipUTF8Recode |
/attachment | id, attachmentId, attachment |
/logout | – |
Dazu kommen immer:
archive: muss ein dem Konto zugewiesener Container sein, sonst HTTP 403. Ohne archive nimmt der Proxy jetzt den zuletzt zugewiesenen Container; vorher kam HTTP 404.filterQuery: nur bei Rolle ADMIN, siehe Abschnitt 3.Vorher
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/search' -d 'query=Rechnung' # HTTP 404, ohne archive fand benno-rest keinen Container
Nachher
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/search' -d 'query=Rechnung' # HTTP 200, Suche im zuletzt zugewiesenen Container des Kontos
Der Pfad hinter rest.php/ darf nur Buchstaben, Ziffern, _, - und / enthalten. URL-kodierte Zeichen
(%3F, %23, …), Punkte und ein leerer Pfad werden mit HTTP 400 abgelehnt.
Vorher
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/search%3Fquery=Rechnung&archive=BennoContainer' # wurde durchgereicht
Nachher
curl -u api:Passwort 'https://benno.example.com/benno/rest.php/search?query=Rechnung&archive=BennoContainer' # HTTP 200; die kodierte Variante oben: HTTP 400
| Code | Bedeutung |
|---|---|
| 401 | nicht angemeldet bzw. falsches Passwort |
| 400 | Pfad leer oder mit unzulässigen Zeichen |
| 403 | Endpunkt nicht freigegeben oder Container nicht zugewiesen |
| 404 | Mail oder Anhang unbekannt oder außerhalb des Filters (bewusst nicht unterscheidbar) |
Abgelehnte Zugriffe protokolliert benno-web über das PHP-Fehlerlog:
/var/log/benno/web.log. Das Verzeichnis ist als Volume eingebunden; mit dem docker run-Aufruf der Appliance liegt die Datei auf dem Host ebenfalls unter /var/log/benno/web.log.error_log schreibt. Ohne eigene Einstellung ist das bei mod_php das Apache-Fehlerlog (Debian: /var/log/apache2/error.log), bei php-fpm dessen Log.Beispiele:
[0:rest_backend] WARNING REST access of api to forbidden endpoint license [0:rest_backend] WARNING REST access of api to disallowed container FremderContainer [0:rest_backend] WARNING REST request of api with invalid path search?query=...
Das Plugin geht standardmäßig über rest.php (/etc/benno-kopano-webapp-plugin/settings.ini, bennopath) und
schickt einen eigenen filterQuery mit. Nach dem Update gilt bei Nicht-ADMIN-Konten der Filter von benno-web. Das
Plugin zeigt also dieselben Mails wie die Weboberfläche. Nach dem Update kurz prüfen: Suche, Mail öffnen, Anhang öffnen.
ERR_REST_404.