luca App: Werbeversprechen gegen API

Die luca App soll eine sichere Öffnung von Restaurants ermöglichen. Eine direkte Anbindung an Gesundheitsämter soll bei Wahrung des Datenschutzes die schnelle Unterbrechung von Infektionsketten gewährleisten. Bereits vor einigen Wochen wurde viel über den zentralisierten Ansatz der Closed Source Anwendung diskutiert.

Der Quellcode der Android Version der luca App wurde inzwischen veröffentlicht. Laut den Entwicklern wird auch die Veröffentlichung des Codes für weitere Komponenten derzeit “vorbereitet”. Was uns hier noch erwartet ist fraglich.

In diesem Artikel sehe ich mir die API der Webapplikation näher an und zeige auf, welche Fehler gemacht wurden und warum das wesentliche Versprechen einer “Verifizierte[n] Telefonnummer” für die Kontaktverfolgung nicht eingehalten wird.

Webapplikation

Eine Komponente, deren Quellcode bisher nicht veröffentlicht wurde, ist die Webapplikation, über die Restaurants den Check-In verwalten können. Nach dem Anlegen eines neuen Restaurants können dort QR-Codes für den Check-In als Tischaufsteller erzeugt werden. Ebenfalls ist der Start einer Webapp möglich, die mit der Webcam den QR-Code innerhalb der luca App scannt. Damit sollen bereits verifizierte Gäste schneller einchecken können. Zudem kann für “analoge” Gäste ein Formular manuell ausgefüllt werden. Auch die Anpassung von Einstellungen und eine Übersicht über derzeit eingecheckte Gäste ist möglich.

Dashboard der Ansicht für Restaurants

Erste Schritte

Zu Testzwecken habe ich mir mein eigenes Restaurant erstellt. Dieses Restaurant wurde mit der E-Mail-Adresse lucaapp.gooduser@ registriert. Zusätzlich habe ich mir einen zweiten Account mit der Adresse lucaapp.baduser@ erstellt.

Ein Restaurant habe ich nur für den gooduser erstellt. Das dazu gehörige Dashboard besitzt die folgende URL: https://app.luca-app.de/app/group/78060917-53ba-4f04-985e-17a69d54429b/location/1b04b932-abe9-40ab-8c5c-10683e3f3f89. Versucht man dieses Dashboard über einen zweiten Browser ohne eine gültige Session aufzurufen, so erfolgt eine direkte Weiterleitung auf die Loginmaske.

Der Versuch eines Logins mit dem baduser und anschließendem erneuten Aufruf der URL zeigte ein unvollständiges Dashboard:

Die Übersicht über die aktuellen Gäste wird nicht angezeigt. Ebenfalls wird die Änderung der Einstellungen verhindert und der Link zur Scanner App wird nicht angezeigt.

Die Adresse wird den Gästen des Restaurants zwar bekannt sein. Die angegebene Telefonnummer könnte jedoch auch eine private Handynummer der Besitzer sein, um auf Anfragen des Gesundheitsamts schneller reagieren zu können. Dementsprechend sollte diese Information geschützt werden.

Die Berechtigungsprüfung scheint an dieser Stelle unvollständig zu arbeiten. Von der Anmeldung an der luca App von einem gemeinsam genutzten Computer muss aus diesem Grund abgeraten werden. Steht die URL zum Restaurant einmal in der Browserchronik, reicht für den Zugriff auf Teildaten ein beliebiger Benutzer aus.

Die Schnittstelle

Für den Abruf der eingeschränkten Informationen ist eine URL erforderlich, die ich bisher nicht erraten konnte. Die Applikation baut auf einer REST API auf, deren Endpunkte ich mir im nächsten Schritt etwas näher angesehen habe.

Tischaufsteller

luca erlaubt die Einteilung des Restaurants in mehrere Tische. Dabei wird für jeden Tisch ein individueller QR-Code bereitgestellt, der dann gescannt werden soll. Nachfolgend zwei Beispiele für Tisch 1 und Tisch 2:

  • https://app.luca-app.de/webapp/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949#eyJ0YWJsZSI6MX0
  • https://app.luca-app.de/webapp/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949#eyJ0YWJsZSI6Mn0

Als Parameter wird hier die scannerId übergeben. Diese gilt für das gesamte Restaurant und ist somit für alle Tische idenTisch. Lediglich im Anchor wird ein Base64 kodiertes JSON mit der Tischnummer mitgegeben: {“table”:1}. TheoreTisch können die Gäste dadurch ihre Tischnummer selbst verändern.

Beim Aufruf der Links öffnet sich die luca WebApp, die eine Verifikation der Telefonnummer durchführt.

Die WebApp erfordert eine Verifikation

Scanner

Für die Erfassung der Gäste durch das Restaurantpersonal sind zwei wesentliche Verfahren vorgesehen. Im Dashboard können dazu Scanner gestartet werden:

  • QR-Code
    Der QR-Code Reader soll einen Scan des QR-Codes aus der luca App ermöglichen. Für mein Testrestaurant hatte dieser die URL https://app.luca-app.de/scanner/cam/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949
  • Kontaktformular
    Das Kontaktformular dient zur Erfassung der Kontaktdaten für Gäste, die die luca App nicht nutzen können oder wollen. Hierbei wird auch auf die Verifikation der Telefonnummer verzichtet. Es hat die URL https://app.luca-app.de/contact-form/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949
Manuelle Anmeldung

locationId

Unabhängig davon, welches Verfahren für die Registrierung gewählt wird, erfolgt ein Zugriff auf den Endpunkt https://app.luca-app.de/api/v3/scanners/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949.

Dieser liefert für die angefragte scannerId die locationId zurück, die auch in der URL zum Dashboard enthalten ist. Die ID wird für einen Teil der weiteren Abfragen benötigt.

Gästeliste

Unter der URL https://app.luca-app.de/api/v3/locations/traces/9c5c3265-1689-4f15-92d7-241507d65d8d kann die aktuelle Gästeliste für mein Testrestaurant angezeigt werden. Diese enthält keine personenbezogenen Daten sondern lediglich eine traceId sowie den Zeitpunkt des CheckIn und CheckOut. Um Zugriff auf diese Liste zu erhalten ist jedoch die accessId notwendig.

accessId

Die accessId wird für mein Restaurant unter https://app.luca-app.de/api/v3/operators/locations/1b04b932-abe9-40ab-8c5c-10683e3f3f89 bereitgestellt. Die hier übergebene ID ist die locationId, die alle Gäste per API erhalten können. Allerdings scheitert der unauthentifizierte Abruf sowie der Abruf mit einem falschen Benutzer mit dem Fehler 404. Somit ist dies der einzige geschützte Endpunkt.

Besucherzahl

Der Endpunkt https://app.luca-app.de/api/v3/scanners/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949/traces/count/current liefert die Anzahl der aktuell eingecheckten Gäste zurück. Für diese URL benötigen wir lediglich die scannerId, die wir bereits aus der URL bei der Anmeldung im Restaurant erhalten haben.

Der Endpunkt erlaubt es somit öffentlich einzusehen, wie viele Gäste derzeit in dem Restaurant erfasst sind. Die scannerId ist für alle Gäste eines Restaurants lesbar. Somit auch für mögliche Konkurrenz, die die Gästezahlen ihrer Mitbewerber im Blick behalten will. Eine Information, die zwar nicht datenschutzrelevant ist, jedoch nicht öffentlich sein sollte. Auch die Verwendung von Tischaufstellern mit unterschiedlichen Tischnummern verhindert den Zugriff nicht. Die Tischnummer in dem QR-Code verweist schließlich immer auf die selbe scannerId. Ein einziges Testessen reicht somit aus, um die Besucherzahl einzusehen.

Das Kernversprechen

Immer wieder wurde die luca App damit beworben, dass mindestens eine verifizierte Kontaktmöglichkeit (konkret die Telefonnummer) vorhanden sei.

Werbeversprechen auf der Startseite

Mit dem nun bekannten Wissen über die API zeigt sich, dass dieses Versprechen nicht eingehalten wird. Vorgesehen sind für den CheckIn im Restaurant durch die Gäste zwei Wege:

  1. QR-Code in der luca App
    Beim Betreten des Restaurants wird der eigene QR-Code in der App vorgezeigt und im Restaurant erfasst. Eine Verifizierung findet bereits bei der Installation der App statt.
  2. QR-Code auf Tischaufstellern
    Beim Scan des QR-Codes werden die Gäste auf eine WebApp geleitet, die die Verifikation der Telefonnummer erfordert.

Mit der manuellen Registrierung durch das Restaurantpersonal gibt es jedoch einen dritten Weg. Vergleichen wir die URLs

  • Manuell https://app.luca-app.de/contact-form/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949
  • Tischaufsteller https://app.luca-app.de/webapp/cf6e23ad-0d2b-4835-8e2a-cd6be17b1949#eyJ0YWJsZSI6MX0

zeigt sich, dass bei beiden URLs die identische scannerId übergeben wird. Folglich können Gäste ebenfalls eine Registrierung über das manuelle Formular unter Angabe falscher Daten durchführen.

Abschließende Bewertung

Die kurze Betrachtung der API hat gezeigt, dass es einige Punkte gibt, an denen es aufgrund fehlender Authentifizierung oder fehlerhafter Berechtigungsprüfungen zu Zugriffsmöglichkeiten auf interne Daten der Restaurantbetreiber kommen kann.

Zudem wird die Verifikation der Telefonnummer nicht unter allen Umständen erzwungen und lässt sich sogar durch die Gäste selbst umgehen. Fehlende einzigartige Zugangsschlüssel für Scannerlinks ermöglichen Gästen den Zugriff auf für das Restaurantpersonal vorgesehene Registrierungsverfahren. Dies widerspricht dem Versprechen einer verifizierten Kontaktmöglichkeit.

Eine App, die mit der Erfüllung “Höchste[r] Datenschutz- und Datensicherheitsstandards” beworben wird, sollte eine zuverlässige Berechtigungsprüfung durchführen und eine klare Zugriffstrennung zwischen Gästen, Mitarbeitern und Restaurantbesitzern aufweisen. Leider verschwimmen hier die Grenzen aufgrund der mehrfach verwendeten Zugriffstokens. Zwar war kein Zugriff auf sensible, persönliche Daten möglich, jedoch schwächt eine derartige Implementierung das Vertrauen in das Gesamtsystem.

Für die Entwickler wird es höchste Zeit die Applikation unabhängig überprüfen zu lassen.

Nachtrag 05.04.2021: Ein externer Pentest wurde bereits am 15.03.2021 veröffentlicht. Darin wird auch das Problem fehlender Berechtigungsprüfung unter Punkt 5.4 beschrieben. Der traces Endpunkt (siehe oben) wird dabei explizit genannt. Offensichtlich wurde der Zugriff als Reaktion mit einer accessId eingeschränkt. Diese accessId bleibt über den Ablauf einer Session hinaus bestehen. Im Pentest wird auch empfohlen eine manuelle Überprüfung für alle Endpunkte durchzuführen. Betrachte ich die beiden Endpunkte für die manuelle Registrierung, den Scanner und die Besucherzahl, so scheint diese Überprüfung nicht stattgefunden zu haben.

Nachtrag 08.04.2021: Die genannten Probleme wurden inzwischen mit einem Update behoben. Für den Zugriff auf den Scanner und die Besucherzahl ist nun die scannerAccessId erforderlich. Diese wird ausschließlich authentifizierten Nutzern unter https://app.luca-app.de/api/v3/operators/locations/1b04b932-abe9-40ab-8c5c-10683e3f3f89 zurückgeliefert. Das Formular für die manuelle Registrierung ist nun über die formId erreichbar. Somit erhalten die Gäste selbst bei Herausgabe des Formularlinks keinen Zugriff auf den Scanner oder die Besucherzahl. Die statischen Tokens lassen sich jedoch weiterhin nicht zurücksetzen. So kann es bei Herausgabe oder Verlust weiterhin zu Missbrauch der Endpunkte kommen. Diese Gefahr besteht insbesondere bei der formId, sofern der Link zum Formular an die Gäste herausgegeben wird oder die Gäste das Formular unbeaufsichtigt nutzen. Folglich könnten weiterhin Registrierungen mit unverifizierter Telefonnummer erfolgen. Das Risiko wurde zwar minimiert, Betreiber von Restaurants und Geschäften haben jedoch keine Möglichkeit gegen einen Missbrauch vorzugehen.

Ein paar Worte zum Bug Bounty Programm

Ja, es gibt ein Bug Bounty Programm. Ich habe keine Ahnung, ob sich das hier überhaupt dafür qualifiziert hätte. Zur Dokumentation sei jedoch erwähnt, dass ich mich dieses Mal bewusst gegen ein Responsible Disclosure Verfahren entschieden habe. Im letzten Jahr habe ich dabei viel zu viel Zeit mit sinnfreien Diskussion verbracht. Das bisherige Verhalten in der Öffentlichkeit der Entwickler deutet nicht darauf hin, dass es hier anders wäre. Insofern erspare ich mir hier den Aufwand. Auch deshalb, weil Restaurants in Deutschland zurzeit ohnehin noch geschlossen haben und die Zeit bis zum Ende des Lockdowns zum Fix ausreichen sollte.

Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments