Schwachstellen in der Dating-App Feeld
(fortbridge.co.uk)- Bei einer Prüfung des Backends der mobilen Dating-App Feeld wurden acht Schwachstellen entdeckt, darunter die Offenlegung von Profilen, das Lesen und Ändern von Nachrichten sowie der Zugriff auf Chat-Anhänge; alle außer der ersten fallen unter Broken Access Control der OWASP Top 10
- Normale Nutzer sehen in der App nur eingeschränkte Informationen, doch bei der Prüfung der Antworten über einen Proxy ließen sich Premium-Informationen wie Alter, Entfernung, Profilfotos und streamUserId von Nutzern abrufen, die ein „Like“ gesendet hatten
- Mehrere Schwachstellen ließen sich ausnutzen, indem Kennungen wie streamUserId, profileId, messageId und channelID aus anderen API-Antworten entnommen und als Request-Parameter eingesetzt wurden; dadurch erweiterte sich der Zugriff auf Nachrichten, Matches, Profile, Likes und sogar das Senden von Chatnachrichten im Namen anderer
- Probleme bei Chat-Anhängen wurden bei normalen Fotos, auf 5–15 Sekunden begrenzten Fotos, normalen Videos und einmal abspielbaren Videos festgestellt; einige Cloudinary- und Stream-CDN-URLs waren ohne Authentifizierung zugänglich
- FORTBRIDGE meldete die Probleme am 8. März 2024 an Feeld; nach mehreren Bitten um Aufschub der Veröffentlichung teilte Feeld am 16. August 2024 mit, Änderungen zur Abmilderung der verbleibenden Punkte umgesetzt zu haben; der Blogbeitrag wurde am 10. September 2024 veröffentlicht
Umfang der bei Feeld festgestellten Schwachstellen
- Ziel war die mobile Dating-App Feeld, ähnlich wie Tinder und Bumble, die Filter nach Entfernung, Alter, Geschlecht, Paaren und Standort anbietet
- Premium-Nutzer können zusätzlich nach Kink-Typen, Dreier-/Gruppenszenarien und gewünschten Beziehungsarten suchen
- Bei der Sicherheitsprüfung wurden acht Schwachstellen festgestellt
- Offenlegung von Profilinformationen gegenüber Nicht-Premium-Nutzern
- Lesen von Nachrichten anderer Personen
- Zugriff auf Foto- und Videoanhänge in Chats ohne Authentifizierung
- Löschen, Wiederherstellen und Ändern von Nachrichten anderer Personen
- Aktualisieren von Profilinformationen anderer Personen
- Erhalten eines „Like“ von einem beliebigen Nutzerprofil
- Senden von Nachrichten in Chats anderer Personen
- Anzeigen der Matches anderer Personen
- Mit Ausnahme des ersten Problems fallen die übrigen Punkte in die OWASP-Top-10-Kategorie Broken Access Control
Gegenüber Nicht-Premium-Nutzern offengelegte Profilinformationen
- Wenn ein Basisnutzer im Likes-Menü der App die Personen ansieht, die ihn gelikt haben, werden nur etwa Name und ein verschwommenes Foto angezeigt
- Fängt man Requests und Responses mit einem Proxy-Tool wie Burp ab, enthielt die Antwort jedoch Informationen auf dem Niveau von Premium-Nutzern
- Alter
- Entfernung
- vollständige Profilfotos
- streamUserId
- Profilfotos waren auf
res.cloudinary.comgespeichert und ohne Authentifizierung zugänglich - Die aus der Antwort erhaltene streamUserId konnte später für die Schwachstelle zum Lesen von Nachrichten anderer Personen genutzt werden
Probleme bei der Zugriffskontrolle für Nachrichten und Matches
- Um Nachrichten anderer Personen zu lesen, wird die streamUserId des Opfers benötigt; dieser Wert wird in mehreren API-Requests offengelegt
- Ein Beispielablauf besteht darin, die streamUserId des Zielnutzers aus der Antwort auf einen
DiscoverProfiles-GraphQL-Request zu entnehmen und diesen Wert anschließend in diemember-Bedingung eines Chat-Channel-Requests einzusetzen - Durch Suchen nach
"text"in der Antwort ließen sich Anzahl und Inhalte der Nachrichten einsehen, die das Opfer gesendet und empfangen hatte - Mit demselben Ansatz konnten auch die zu einzelnen Nachrichten gehörenden messageId-Werte ermittelt werden; diese werden zum Löschen, Wiederherstellen und Ändern von Nachrichten verwendet
- Ändert man den verwundbaren Parameter
profileIdinChatListQuery, ließen sich die Matches anderer Nutzer anzeigen- Zu den einsehbaren Informationen gehörten imaginaryName, Alter, Fotos, Geschlecht, sexuality, status und Geburtsdatum
Nicht authentifizierter Zugriff auf Chat-Anhänge
- In Chats geteilte Anhänge werden in Fotos und Videos unterteilt
- Fotos sind entweder normale, wiedergebbare Fotos oder auf 5–15 Sekunden begrenzte Fotos
- Videos sind entweder normale, wiedergebbare Videos oder einmal abspielbare Videos
- Normale Fotos werden von der Feeld-App zu
api.cloudinary.comhochgeladen, und als Antwort wird eine photo_id zurückgegeben- Anschließend wird das Foto nach
feeld.cokopiert und authentifizierten Nutzern bereitgestellt - Es werden Pfade der Form
cdn/chat-attachment/<receiver_profileId>/<photo_id>oder<sender_profileId>/<photo_id>verwendet - Der profileId-Teil des Pfads konnte auf eine beliebige Zeichenkette mit mindestens einem Zeichen verkürzt werden; authentifizierte Nutzer erhielten das Foto trotzdem zurück
- Ein Pfad mit vorangestelltem
/v1/gab die URL des bei Cloudinary gespeicherten Originalfotos zurück; diese URL war ohne Authentifizierung zugänglich
- Anschließend wird das Foto nach
- Bei zeitlich begrenzten Fotos wird beim Upload ein zusätzlicher Parameter wie
visibilityMilliseconds:15000verwendet- Der Empfänger-Endpunkt löscht das Foto 5–15 Sekunden nach dem Zugriff, danach ist es nicht mehr erreichbar
- Der Endpunkt mit der profileId des Uploaders gab das Foto auch nach 5–15 Sekunden weiterhin an authentifizierte Nutzer zurück
- Der
/v1/-Pfad gab eine Cloudinary-URL zurück, die ohne Authentifizierung zugänglich war
- Bei Videos war die URL sowohl bei normalen Videos als auch bei einmal abspielbaren Videos in der Chatnachricht enthalten
- Normale Videos werden zu
us-east.stream-io-cdn.comhochgeladen - Für einmal abspielbare Videos wird ein Upload-Flow über
chat.stream-io-api.comgenutzt - Wenn ein Angreifer die URL über die zuvor beschriebene Schwachstelle zum Lesen von Nachrichten erhielt und
u0026durch&ersetzte, konnte er das Video ohne Authentifizierung ansehen
- Normale Videos werden zu
- Einmal abspielbare Videos waren für den Angreifer erneut abspielbar, während sie in der App des Empfängers nach einmaligem Ansehen als
video expiredangezeigt wurden
Manipulation von Nachrichten, Profiländerungen und gefälschte Likes
- Über den Endpunkt
chat.stream-io-api.com/messages/<messageId>konnten mit den Methoden DELETE und PUT Nachrichten anderer Personen bearbeitet werden - Gelöschte Nachrichten erscheinen im Chat als
This message was deleted, doch wenn ein Angreifer denselben DELETE-Request aufrief, konnte er die ursprüngliche Nachricht zurückerhalten - Ein Angreifer konnte Nachrichten mithilfe der messageId ändern, auch ohne Teilnehmer des Chats zu sein
- Wenn das Opfer auf eine Benachrichtigung tippte, sah es die geänderte Nachricht
- Unter der Nachricht erscheint zwar die Markierung
edited, aber nicht, wer sie geändert hat - Kontonamen sind nicht eindeutig und können bearbeitet werden
- Wird der verwundbare Parameter
idim GraphQL-RequestProfileUpdatedurch die ID des Opfers ersetzt, lassen sich Profilinformationen wie Name, sexuality, Alter und Bio aktualisieren - Im GraphQL-Request
ProfileLikekonnte man im eingeloggten Zustand als profile#1 so tun, als habe profile#2 profile#3 ein „Like“ gesendet- Im Beispiel wurde von einem beliebigen Profil ein Like an das eigene Profil gesendet; anschließend wurde dieses Like in der Likes-Liste eines Premium-Kontos angezeigt
Nachrichten in Chats anderer Personen senden
- Ein Angreifer konnte Nachrichten in Chats anderer Personen senden, auch ohne Teilnehmer des Chats zu sein
- Benötigt wird die channelID, die über die zuvor beschriebene Schwachstelle zum Lesen von Nachrichten ermittelt werden kann
- Sendet man einen POST-Request an den Pfad
channels/messaging/<channelID>/message, wird dem entsprechenden Channel eine Nachricht hinzugefügt - Das Opfer erhält eine Benachrichtigung und kann die Nachricht sehen
- Das System zeigt die Benachrichtigung so an, als stamme sie vom Namen des Angreifers, doch der Angreifer kann seinen Profilnamen ändern, und Namen sind nicht eindeutig
Offenlegungs-Zeitplan
- Am 8. März 2024 meldete FORTBRIDGE alle Probleme an Feeld
- Am selben Tag bat Feeld um die Informationen zu den für Tests verwendeten Konten
- Am 2. April 2024 bat FORTBRIDGE um ein Update; Feeld erklärte, man untersuche die Sache, und bat darum, die Veröffentlichung zurückzustellen
- Am 28. Mai 2024 teilte Feeld mit, mehrere Korrekturen ausgerollt zu haben, und bat um eine Verzögerung von bis zu zwei Wochen, um zu prüfen, ob die gefundenen Punkte behoben seien
- Am 8. Juni 2024 waren drei Monate seit der ersten Offenlegungs-E-Mail vergangen
- Am 15. Juli 2024 antwortete Feeld, dass einige Probleme komplexere Korrekturen erforderten
- Am 4. August 2024 bat Feeld darum, die Veröffentlichung bis zur Behebung der verbleibenden Punkte zurückzustellen
- Am 16. August 2024 teilte Feeld mit, Änderungen zur Abmilderung der verbleibenden Findings umgesetzt zu haben
- Am 8. September 2024 waren sechs Monate seit der ersten Offenlegung vergangen
- Am 10. September 2024 wurde der Blogbeitrag veröffentlicht
- Im August 2025 wurde die Forschung auf der DEF CON 33 vorgestellt
1 Kommentare
Hacker-News-Kommentare
Es wirkt so, als seien Berechtigungsprüfungen nur im Frontend implementiert worden, und zwar nicht nur bei ein oder zwei Endpunkten, sondern offenbar fast durchgängig
Konzeptionell ist das ein leicht vermeidbarer Fehler, aber ich habe so etwas so oft gesehen, dass man ähnliche Fehler kaum noch eingestehen will
Die Lösung „alle Berechtigungen im Backend prüfen“ fühlt sich ein wenig an wie bei Buffer Overflows die Forderung „überall Grenzprüfungen einbauen“. Die ganze Community weiß, was zu tun ist, aber alle dazu zu bringen, es konsequent umzusetzen, ist nicht einfach
Berechtigungsprüfungen dagegen passieren an klaren Grenzen und hängen mit der Art zusammen, wie eine Anwendung entworfen ist. Wann immer ich Einfluss auf die Projektentwicklung nehmen konnte, habe ich darauf bestanden, die Entwicklung der Backend-API und den Frontend-Client-Code klar zu trennen. Meiner Erfahrung nach lassen sich solche Probleme so viel leichter vermeiden und testen, und eine Entwickler-API bekommt man „gratis“ dazu. Ehrlich gesagt ist das der Hauptgrund, warum ich diesen Ansatz bevorzuge
Aufgefallen ist es, weil sich der Besitzer eines lamp-Accounts meldete, dass plötzlich all seine Daten verschwunden waren. In den Logs sah man, dass Google Bot alle „Delete“-Links auf einem internen Admin-Screen angeklickt hatte. Weil JavaScript opt-in ist, war das möglich. Ich habe den Entwickler angerufen und erklärt, was da passiert war, und an dem Tag viel Vertrauen in Webleute verloren
Ich markiere das jedes Mal, wenn ich es sehe, aber es beunruhigt mich ziemlich, wie wenig oft über den Umfang einer Client-API nachgedacht wird
Ich würde gern Juniors, No-Code und AI-Code die Schuld geben, aber ich bin selbst genauso faul, also schüttle ich nur den Kopf und gehe weiter
Das ist ein sehr guter Grund, keine exakten persönlichen Daten anzugeben, etwa das Geburtsdatum
Gerade Dating-Apps scheinen solche Angaben zu verlangen, aber man fährt besser damit, sie nicht exakt einzutragen. Es ist besser, einen Wert anzugeben, der etwa ein Jahr vom echten Geburtstag abweicht
Diese Dating-App ist nicht besonders bekannt, richtet sich aber an queere Nutzer und an Menschen mit anderen Vorlieben wie BDSM oder Gruppensex. In vielen Teilen der Welt sind solche Informationen, ohne dass man es extra sagen müsste, hochsensibel
Diese Woche war die App oft in den Medien, weil sie angeblich gut Geld verdient
https://www.theguardian.com/technology/article/2024/sep/08/t...
Wenn man die App-Kategorie bedenkt, ist das ein Versagen auf dem Niveau von krimineller Fahrlässigkeit
Die einzige wirksame Abschreckung scheinen Haftandrohungen in den USA und der EU, Datenversicherungen und die Kosten solcher Versicherungen zu sein. Wenn die Fotos nichts sind, was man auf LinkedIn hochladen würde, sollte der Preis astronomisch sein
Natürlich dürfen die Anreize nicht dazu führen, Vertuschung zu fördern
Online-Dating ist ein einziges Chaos. Es gibt nur zwei oder drei Unternehmen mit Diensten, die man überhaupt als nützlich bezeichnen kann, und diese Firmen sind böse oder inkompetent oder beides
Vielleicht braucht es jetzt so etwas wie einen föderierten Open-Source-Datingdienst. Zumindest etwas, das keine Daten verkauft, keine Nacktbilder leakt und nicht dazu führt, dass Menschen verprügelt, vergewaltigt oder ermordet werden. Leichter gesagt als getan natürlich
ActivityPub hat strukturell sogar das Potenzial dafür, indem es Person-Records veröffentlicht. Vor allem wenn man Anforderungen von nichtmonogamen, nichtheterosexuellen und gendernonkonformen Menschen priorisiert, gibt es enorm viel Raum für Innovation
Dating-Apps sind allerdings ein wirklich schwerer Markt. Damit es nützlich wird, braucht man in einer bestimmten Region eine kritische Masse an Nutzern, und sobald man monetarisiert, wird die App zwangsläufig weniger nützlich. Es gibt einen Grund, warum okcupid kaputtging, nachdem es aufgehört hatte, quasi gemeinnützig zu sein
Und dann ist da noch das Moderationsproblem
Wenn man daraus digitale Kopien machen will, ist das natürlich das Recht jedes Einzelnen, aber man sollte wissen, dass kein System jemals sicher genug sein wird, um Leaks und Verbreitung zu verhindern, und es auch künftig nicht sein wird
Gerade junge Menschen bedenken die langfristigen Folgen und die Scham, die daraus entstehen kann und wahrscheinlich entstehen wird, oft nicht. Solche Funktionen anzubieten heißt nur, negative Folgen einzuladen
Wirklich grauenhaft. Offensichtlich wurde über Sicherheit überhaupt nicht nachgedacht
Ich bin Spieleentwickler, und diese Firma hat weniger Aufwand darauf verwendet, ihre Nutzer zu schützen, als wir darauf verwenden, unsere Spiele fair zu halten. Sie sollten durch Klagen ruiniert werden
Schon bevor mir klar wurde, dass die App voller Bugs ist, war ich sehr überrascht, dass der Interessenbereich überhaupt keinen Kontext liefert. Zum Beispiel hatten fast alle Domination oder Submission als Interesse angegeben, aber es gab keinerlei Kontext dazu, welche Rolle sie eigentlich suchten. Wenn man in dieser Szene nicht versteht, wie grundlegend falsch das ist, versteht man vermutlich insgesamt gar nichts
Nachrichten und private Fotos sind etwas anderes
Provokant gesagt: Das ist ein GraphQL-Problem
GraphQL erlaubt dem Frontend, Daten abzufragen. Das ist zwar schick, ist aus Backend-Sicht aber sehr intransparent und wird oft mit Third-Party-Bibliotheken implementiert, die von Zugriffskontrolle überhaupt nichts verstehen.
Wenn man die Zugriffskontrolle nicht direkt in der Datenbank selbst implementiert, ist es im Backend-Code sehr schwierig, GraphQL-Abfragen aufzulösen und herauszufinden, welche Datensätze zurückgegeben oder eingeschränkt werden müssen. Es in der Datenbank zu machen ist nicht die schlechteste Lösung und auf jeden Fall besser, als es im Frontend zu tun.
Um im Backend eine saubere Zugriffskontrolle umzusetzen, muss man die Abfragen verstehen, das Datenbankschema kennen und Modelle, Klassen, Funktionen usw. bauen, die beurteilen können: „Kann ein user_id XXX dieses Bild in diesem Kontext sehen oder nicht?“ In GraphQL ist es viel einfacher, das im Frontend zu implementieren, daher haben sie es offensichtlich so gemacht.
Das heißt weder, dass die GraphQL-Implementierung gut war, noch dass das Problem ausschließlich bei GraphQL liegt. Gemeint ist, dass GraphQL komplexe Sicherheitssituationen schwieriger macht, weil das Backend die Abfragen gerade nicht verstehen muss, und dass dieser Fehler dadurch leichter passiert.
[0] Zum Beispiel kann ein bestimmtes Bild im Benutzerprofil öffentlich zugänglich sein, aber nur für Matches sichtbar sein, oder nur im Chat-Kontext sichtbar sein (außer in Gruppenchats), oder für blockierte Nutzer jederzeit unzugänglich sein. Schon dieser eine Fall kann massenhaft komplizierte Edge Cases erzeugen.
Man muss weder am AST herumbasteln noch den Kontext der übrigen Abfragen verstehen. Im Resolver, der Fotos holt, muss man nur beantworten: „Darf Benutzer ABC die Fotos von Benutzer XYZ sehen?“ Wenn das ineffizient ist, kann man einige Daten vorab laden oder einen dataloader verwenden.
Anders sieht es natürlich aus, wenn man eine magische Bibliothek verwendet, die GraphQL in SQL umwandelt.
https://hasura.io/docs/2.0/security/allow-list/
Eine einfache Idee ist, die Autorisierung im Datenmodell selbst umzusetzen. GraphQL delegiert dann
getundlistan ein Ressourcenmodell, das Autorisierung abhängig vom Request-Kontext implementieren kann.[1] https://www.apollographql.com/docs/apollo-server/security/au...
[2] https://docs.graphene-python.org/projects/django/en/latest/a...
Erstaunlich verantwortungsvolle und rücksichtsvolle Offenlegung
Nicht besonders überraschend. Ich nutze die App, würde aber sagen, sie ist ungefähr so inkompetent gebaut wie meine Banking-App. Vielleicht sogar schlimmer, denn sie funktioniert fast nie richtig.
Ich weiß nicht, wie man so etwas überhaupt bauen konnte.
Bei dieser App und bei Fetlife sieht man deutlich das Problem, dass solche Communities bei der ersten App bleiben, die auf den Markt kommt, ganz unabhängig von der Qualität.
Dann gab es vor Kurzem einen Flag Day, an dem sie gleichzeitig eine neue App und neue Server für alle ausgerollt haben, und die meisten konnten sich nicht einmal anmelden. Wer sich doch anmelden konnte und zahlender Kunde war, verlor seine Premium-Vorteile; Likes und Chats waren verschwunden und es gab noch weitere Probleme. Ich konnte mich am Ende gar nicht mehr anmelden und habe die App dann aufgegeben.
Ehrlich gesagt überrascht mich eher, dass die Forscher mit der Offenlegung so lange gewartet haben.
Wenn man so einem schlechten Startup bei einer derart gravierenden Datenschutzlücke sechs Monate gibt, damit es sie schließt, missbraucht es in dieser Zeit weiter das Privileg, solche Informationen überhaupt sammeln zu dürfen. Meiner Meinung nach sollte man nur zwei Monate geben und dann veröffentlichen. Sie müssen lernen, dass man mit den privaten Informationen anderer Menschen nicht würfelt.
Zum Beispiel: https://news.ycombinator.com/item?id=41517747