Hotel: Check-in 🤝 Daten: Check-Out
Guter Schlaf ist wichtig. Das wissen auch Hotels – und versprechen mehr davon, wenn man schon vor Ankunft online eincheckt. Natürlich ist es auch günstiger für die Betreiber, Personal an der Rezeption einzusparen und stattdessen eine Maschine hinzustellen. Oder noch besser: den Check-In einfach komplett durch die Gäste auf ihren Smartphones erledigen zu lassen.
Das ist schon auch komfortabel, aber spätestens seit die Sicherheitslücken bei der Hotelkette Numa bekannt wurden, haben wir bei der Kombination aus “Online-Check-In” und “mehr Schlaf” aber doch ein paar Fragezeichen im Kopf. Denn uns interessiert natürlich: Wie funktioniert der Check-In technisch und können wir ihm vertrauen?
Spoiler: Nope, leider nicht…
Kommt mit auf eine Datenreise.
## Can I have a little Urlaub? 👉👈
Sommerzeit heißt Reisezeit. Auch wir waren viel unterwegs, haben das ein oder andere Hotelsystem verwendet und irgendwann ist es passiert – uns sind Daten, Rechnungen und Ausweiskopien der anderen Hotelbesucher*innen entgegen gefallen. Vorbei war es dann mit dem guten Schlaf.
Aber von vorne: Nach einer längeren Zugreise schon vor der Ankunft im Hotel online einchecken kann sehr bequem sein. Mitunter verlangen Check-In-Formulare aber eine ganze Menge Daten, die gar nicht unbedingt nötig wären.
So auch in unserem Fall: Ohne Name, Geburtsdatum, Anschrift, eine Unterschrift und sogar ggf. Fotos von den Ausweisdokumenten kein Zimmerschlüssel. Praktisch: Während des Aufenthalts kann dann über das gleiche Portal auch gleich ein Wasserkocher für’s Zimmer dazugebucht werden – und nach dem Aufenthalt gibt es dort dann auch direkt Zugriff auf die Rechnung.
## Kleine Web-App, große Wirkung
Die Software, um diese Daten zu erfassen, schreiben die Hotels in der Regel nicht selbst, sondern das machen Softwaredienstleister (wie in vielen anderen Bereichen auch). Im heutigen Fall die Firma _likeMagic AG_ aus der Schweiz🍫. Diese bietet eine Plattform, über die Hotelmitarbeitende sämtliche Arbeiten, die in so einem Hotel anfallen, mit einer Web-App verwalten. Und weil es natürlich ~~bequemer~~ billiger ist, wenn die Gäste sich selbst einchecken und den Zimmerschlüssel aufs Telefon bekommen, gibt es noch eine weitere WebApp für die Gäste.
Damit diese für jedes Hotel bzw. jede Hotelkette auch in den Markenfarben (und -Domains) des Hotels erstrahlt, ist die Gäste-WebApp unter einer Subdomain der Hotelwebseite erreichbar. Damit ist auch von _likeMagic_ als Serviceanbieter erstmal nichts zu sehen. Als Beispiel-URL für diesen Blogpost nehmen wir `https://my.examplehotel.invalid`.
## Check-In? Check-Out!
Ein paar Tage vor unserem heiß erwarteten Hotelbesuch ist es dann soweit: Wir bekommen eine E-Mail mit dem Check-In-Link für unseren Aufenthalt.
Also los, Check-In-Formular geöffnet und mit Daten befüllt. Nachdem wir alles eingegeben haben, müssen wir unseren virtuellen Meldeschein “unterschreiben”. Das geht entweder per Rumkritzeln auf dem Smartphone oder als Kunstwerk per Maus, aber _likeMagic_ bietet auch eine Komfort-Funktion an und generiert automatisch eine Unterschrift: einfach den eigenen Namen in traumhaft schöner Schreibschrift. Und damit sind wir auch schon fertig mit dem Check-In.
Wir haben uns dann doch fürs rumkritzeln entschieden 🖍️. Und ja: Der Hinweis mit dem Gesetzgeber steht da wirklich so ☝️
Aber als gute zerforschis haben wir natürlich schon laaaaaange vorher die Entwicklungstools unseres Browsers geöffnet 👩🔬. Die protokollieren unter anderem die ganze Zeit mit, welche Daten die Website so an ihre Server sendet. Zuerst werden die eingegebenen Daten losgeschickt, und dann zum Schluss unsere “Unterschrift” hochgeladen. Das ganze quittiert der Server und sagt uns zur hochgeladenen Unterschrift gleich noch, unter welchem Dateinamen er sie abgespeichert hat und wie groß sie ist.1
{
"createdAt": "2025-09-05T12:34:51.123456789Z",
"updatedAt": "2025-09-05T12:34:51.123456789Z",
"version": 0,
"tenant": {
"id": 69,
"name": "zerdreams",
"description": "ZER Hotels für Guten Schlaf und Sichere Daten",
"createdAt": "2020-09-21T01:23:45.123456Z",
"updatedAt": "2020-09-21T01:23:45.123456Z",
"version": 0
},
"id": 2342420,
"blobCreatedAt": "2025-09-05T12:34:51.123456789Z",
"fileName": "ABCDEFGH-1/SIGNATURE_DOCUMENT.png",
"contentType": "image/png",
"contentLength": 2342,
"metaData": {
"ownerId": "ABCDEFGH-1",
"magicFileType": "SIGNATURE_DOCUMENT",
"originalFilename": "SIGNATURE_DOCUMENT.png"
},
"ownerId": "ABCDEFGH-1",
"tenantName": "zerdreams"
}
Das ist natürlich sehr freundlich vom Server, aber keine Information, die wir eigentlich benötigen. Diese Redseligkeit macht uns schon etwas stutzig – also gucken wir in den Code.
## Was will uns der Server damit sagen?
Als klassische sogenannte “Single-Page-Applikation”2 wird auch hier wieder schon beim Öffnen der WebApp ganz viel Code für den Browser geladen – unabhängig davon, ob die Funktionen für diesen User/Einsatzzweck relevant sind, oder nicht. Dabei taucht dann auch beim groben Drüberlesen schnell eine Funktion namens `downloadFile` auf: Diese nimmt einen Dateinamen und versucht, die Datei vom Server abzurufen.
Der Endpunkt, um Dateien abzurufen ist `https://my.examplehotel.invalid/api/guest-journey-service/{magicId}/files?fileName={name}`. Die `magicId` ist dabei eine längere zufällige Zeichenkette, die im Check-In-Link enthalten ist, den wir anfangs per Mail bekommen haben.
Beim ersten Versuch diese URL direkt aufzurufen, bekommen wir nur eine Fehlermeldung, dass wir nicht angemeldet sind. Denn dieser Endpunkt braucht als Authentifizierung einen `Bearer`-Token von einem eingeloggten Nutzer. Na gut, dann müssen wir den wohl zuerst besorgen…
Wir haben zwar keinen Account bei dem Hotel, klicken aber trotzdem auf den großen “Login”-Button auf der Hauptseite.
Und siehe da: Auf der Login-Seite gibt es auch gleich einen Registrierungslink und nur wenige Sekunden später halten wir unseren neuen Account (und den dazugehörigen `Bearer`-Token) in den Händen und können es nochmal probieren. Mit dem Account klappt es dann direkt und wir können unsere wunderbar generierte Unterschrift nochmal betrachten.
Dabei fällt unser Blick genauer auf den Dateinamen: `ABCDEFGH-1/SIGNATURE_DOCUMENT.png`. Der besteht aus drei Teilen: `ABCDEFGH-1` ist unsere Buchungsnummer, `SIGNATURE_DOCUMENT` die Art der Datei und `png` natürlich die passende Dateiendung für das Unterschriften-Bild, das wir hochgeladen haben.
## Die einzige Form von weltoffen, die nicht okay ist
Doch als wir eine mitreisende Person nach ihrem Buchungscode fragen (sagen wir mal `STUVWXYZ-1`) und diesen ausprobieren, sind wir schockiert: Auch `STUVWXYZ-1/SIGNATURE_DOCUMENT.png` können wir abrufen und sehen … die automatisch generierte Unterschrift mit dem Namen unserer mitreisenden Person. Selbst den hochgeladenen Ausweis der Person können wir abrufen, direkt unter `STUVWXYZ-1/IDENTIFICATION_DOCUMENT.jpg` – dass die Datei so heißen müsste, wissen wir aus dem Code.
Uff. Puh. Belastend. Wir haben gerade erst eingecheckt und schon finden wir so etwas? Datei für Datei die Buchungsanhänge runterladen zu können, ist schon schlimm – und eigentlich könnten wir hier auch schon aufhören. Die Erfahrung zeigt aber, dass Sicherheitslücken Rudeltiere sind und meist zusammen auftreten. Dann schauen wir mal lieber genauer hin.
## Zimmerservice? Einmal alles bitte.
_likeMagic_ stellt praktischerweise eine gute API-Doku bereit, sodass wir gleich nachlesen, welche weiteren Schnittstellen wir uns anschauen könnten. Das ist gute Praxis, allerdings müssen die dort beschriebenen Schnittstellen (genauso wie grundsätzlich **alle** Schnittstellen) ausreichend sicher sein.
So erfahren wir, dass `https://my.examplehotel.invalid/api/guest-journey-service/files/{BOOKING_CODE}/list` eine Liste aller Dateien zurück gibt, die zu einer Buchungsnummer gehören. Das ist die Unterschrift, ggf. das Ausweisfoto sowie am Ende die Rechnung 💸😭.
## 🎶 A, B, C, D, E, F, G… 🎶
Auch für diesen Endpunkt müssen wir zwar angemeldet sein, aber auch hier gilt: Welcher Nutzeraccount die Anfrage stellt, ist offensichtlich völlig egal. Unser erster Gedanke: Naja, dann muss man ja immerhin die Buchungsnummer (8 Großbuchstaben + eine Zahl) kennen, die kann man wenigstens nicht sofort erraten. Die Realität holt uns leider sofort ein: Die Software wirft einem anscheinend _sämtliche_ Dateien zurück, bei denen die Buchungsnummer mit den angegebenen Zeichen anfängt.
Gäben wir also beispielsweise die Buchstaben `ZER` als Buchungscode an, bekämen wir wohl _alle_ Dateien zu _allen_ Buchungen, die mit `ZER` anfangen – inklusive ihrem Inhalt. Oh no!
GET https://my.examplehotel.invalid/api/guest-journey-service/files/ZER/list
[
{
"fileName": "ZEROHNOO-1/ZEROHNOO-1-1.pdf",
"contentType": "application/pdf",
"contentLength": 12345,
"blobCreatedAt": "2025-01-01T01:01:01.123Z",
"metaData": {
"ownerId": "ZEROHNOO-1",
"folioId": "ZEROHNOO-1-1",
"magicFileType": "INVOICE"
},
"ownerId": "ZEROHNOO-1",
"content": "[...]",
"signedUrl": null
},
// ... (weitere 23MB JSON-Daten 🤯)
]
Weil die Buchungsnummern immer mit einem Großbuchstaben beginnen und schon ein Buchstabe reicht, um die Suche zu starten, könnte man mit nur ganzen _*checks notes*_ 26 Anfragen die Dateien aller Buchungen abrufen3. Mist 🍞.
## Wir würden dann gerne Zählen, bitte.
Wir schätzen, dass alleine bei der Hotelkette, bei der wir selbst waren – McDreams – mehr als 500.000 Dateien von rund 200.000 Buchungen abrufbar gewesen wären – inklusive 90.000 Ausweisdokumenten.
Und das war nur eine Hotelkette. Eine schnelle Suche liefert eine Liste von fast 50 Instanzen der _likeMagic_ -WebApp, die mutmaßlich ebenso betroffen waren.
## Vor dem Schlafen, nach dem Essen, Lückenmeldung nicht vergessen
Nun haben wir Lücken gefunden, die sogar gleich eine ganze Reihe von Hotels betreffen. Damit geht die eigentliche Arbeit für uns erst los: alles sauber aufschreiben und dokumentieren. Diesen Report über die gefundenen Lücken schicken wir dann an den Hersteller und das CERTBund beim BSI.
Der Hersteller antwortet (trotz Meldung an einem Sonntagabend!) prompt: bereits nach 2 Stunden bekommen wir eine Antwort und die Bestätigung, dass die Lücken geschlossen seien – was bei einem kurzen Test auch zu stimmen scheint.
Auch der Hinweis, dass wir keinen Sicherheitskontakt finden konnten, wurde dankend aufgenommen. Wir empfehlen grundsätzlich immer allen, einen Sicherheitskontakt mittels des security.txt-Standards bereitzustellen. Ein paar Tage später tauchte zwar keine security.txt, aber immerhin eine frische Vulnerability Disclosure Policy in ihrem Helpcenter auf. Das ist eine gute Reaktion, die wir an dieser Stelle auch mal explizit loben wollen – auch wenn es nie zu einer solchen Lücke hätte kommen dürfen.
Ganz positiv fällt unser Fazit zum Umgang mit der Lücke jedoch nicht aus: Bis heute wissen wir von keiner Information an die betroffenen Hotelgäste. Diese sollten darüber informiert werden, dass ihre Daten gefährdet waren, so wie es die DSGVO auch vorsieht.
## Warum liegen hier überhaupt Ausweise rum?
Zum 01.01.2025 wurde das Bundesmeldegesetz angepasst, die “besondere Meldepflicht in Beherbergungsstätten” aus §29 und §30 BMG wurde für deutsche Staatsangehörige aufgehoben – aber halt auch nur für diese.
Menschen, die nicht aus ‘schland 🇧🇪 stammen, müssen weiterhin ihre Daten und Wohnanschrift abgeben und ihren Ausweis zum Vergleich bereitstellen. Üblicherweise reicht da der Vergleich durch einen kurzen Blick auf den Perso an der Rezeption. Sobald aber der Check-In online passiert, kommen Hotels und Softwareanbieter auf interessante Ideen, wie man das denn über das Internet bewerkstelligt.
Was jetzt Deutsche weniger gefährlich macht als alle anderen Menschen können wir uns (außer mit einer gehörigen Portion ~~Rass~~ Patriotismus) nicht erklären. Deshalb gilt hier wie immer: Daten, die nicht zwingend benötigt werden, sollte man gar nicht erst erfassen. Und ist der Grund für bereits erfasste Daten weggefallen, sollten die auch schnellstmöglichst gelöscht werden. Besonders diese personenbezogenen Daten sind nunmal kein Öl, sondern toxischer Abfall. Und Daten die man nicht (mehr) hat, können auch nicht unbeabsichtigt wegkommen :)
Die allerbeste Lösung für das Problem ist aber eine Anpassung des Bundesmeldegesetzes: einfach keinerlei Datenerfassung mehr. Denn wer sie nicht von Menschen mit einer bestimmten Staatsbürgerschaft braucht, braucht sie von allen anderen auch nicht. Das ist auch die Position des Hotelverband Deutschland.
## Schluss. Schlafen.
Liebe Hotels, ab jetzt bitte keine Lücken mehr, damit wir endlich wieder ruhig schlafen können. Wir machen das alles ehrenamtlich in unserer Freizeit. Guter Schlaf ist wichtig. Auch für uns… 😴4
## Timeline
* 2025-09-05: Beginn der Analyse, Erste Lücke entdeckt
* 2025-09-06: Zweite Lücke entdeckt; Bestätigt, dass auch andere Hotelketten betroffen sind
* 2025-09-07 20:23 Uhr: Meldung der Lücke an das Unternehmen und das CERTBund
* 2025-09-07 22:34 Uhr: Antwort des Unternehmens, Lücke geschlossen
## 🤝
Unsere Recherchen haben wir mit Jacob von der ZEIT geteilt, den Artikel findet ihr hier.
An solch einem Artikel sitzen wir als Kollektiv deutlich länger als eine Woche, vom Finden der Lücken, über das Schreiben der Reports, den Umgang mit den betroffenen Unternehmen bis zur Veröffentlichung dieses Posts.
Falls euch dieser Artikel gefallen hat, könnt ihr uns gerne unterstützen. Und wer uns bereits unterstützt - nochmals vielen Dank! (Kleiner Hinweis: Wir mussten schon wieder unsere IBAN austauschen)
* * *
1. Die Inhalte des folgenden JSON-Snippets haben wir fiktionalisiert, die Struktur ist beibehalten. ↩︎
2. https://de.wikipedia.org/wiki/Single-Page-Webanwendung ↩︎
3. Falls ihr euch fragt, warum der letzte Blogpost so lange her ist: Wir haben uns fortgebildet und können jetzt nicht nur Zahlen hochzählen, sondern auch das ganze Alphabet (in Schrift und Gesang). ↩︎
4. Dieser Satz wurde sehr müde mitten in der Nacht geschrieben. ↩︎