1 Punkte von GN⁺ 2024-09-13 | 1 Kommentare | Auf WhatsApp teilen
  • 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.com gespeichert 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 die member-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 profileId in ChatListQuery, 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.com hochgeladen, und als Antwort wird eine photo_id zurückgegeben
    • Anschließend wird das Foto nach feeld.co kopiert 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
  • Bei zeitlich begrenzten Fotos wird beim Upload ein zusätzlicher Parameter wie visibilityMilliseconds:15000 verwendet
    • 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.com hochgeladen
    • Für einmal abspielbare Videos wird ein Upload-Flow über chat.stream-io-api.com genutzt
    • Wenn ein Angreifer die URL über die zuvor beschriebene Schwachstelle zum Lesen von Nachrichten erhielt und u0026 durch & ersetzte, konnte er das Video ohne Authentifizierung ansehen
  • Einmal abspielbare Videos waren für den Angreifer erneut abspielbar, während sie in der App des Empfängers nach einmaligem Ansehen als video expired angezeigt 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 id im GraphQL-Request ProfileUpdate durch die ID des Opfers ersetzt, lassen sich Profilinformationen wie Name, sexuality, Alter und Bio aktualisieren
  • Im GraphQL-Request ProfileLike konnte 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

 
GN⁺ 2024-09-13
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

    • Ich finde nicht, dass die beiden Dinge gleich sind. Prüfungen auf Buffer Overflows sind sehr konkrete Implementierungs- und Sprachdetails und können überall in einer Codebasis auftreten
      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
    • Wenn man das schon verwechselt, sollte man serverseitigen Code nicht anfassen
    • Ich habe einmal einen Webentwickler dabei erwischt, wie er Frontend-Authentifizierung mit einem simplen JavaScript-Dialog umgesetzt hatte. Das Passwort stand in JS und wurde einfach verglichen
      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
    • Wenn man im Backend eine „automatische DB-API“ verwendet, kann so etwas meiner Meinung nach sehr leicht passieren. Mir fallen zum Beispiel manche automatischen GraphQL-Konfigurationen ein
      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
    • Bei mobilen Apps ist das leider ziemlich verbreitet. So nach dem Motto: „Wer wird sich eine mobile App schon genauer ansehen?“
      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...

    • In letzter Zeit hat man oft den Eindruck, dass es viel profitabler ist, schlechte Dinge zu bauen, als gute
    • The Guardian sollte das sehen
  • Wenn man die App-Kategorie bedenkt, ist das ein Versagen auf dem Niveau von krimineller Fahrlässigkeit

    • Ich war einmal so ein Billigauftragnehmer. Die Chefs interessierten sich nur für Deadlines und für Bugs, die Kundenreviewern auffallen würden
      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
    • Das war wohl kein Witz. Solche Schwachstellen wären schon vor 10 Jahren peinlich gewesen
  • 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

    • Ich denke seit Jahren über so etwas nach, aber ich habe neben meinem Hauptjob nicht genug freies Dopamin, um es zu bauen
      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
    • Ich finde, Nacktbilder sollten analog bleiben. Dann kann man ihre Verbreitung fast vollständig und absolut kontrollieren
      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

    • Nicht nur über Sicherheit, sondern offenbar über gar nichts
      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
    • Man sollte bedenken, dass Profile in Dating-Apps prinzipiell für alle zugänglich sind. Man öffnet die App, und Profile erscheinen. Es gibt kein ACL oder so etwas
      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.

    • Ziemlich einfach. Man schützt jeden Resolver, der Daten holt, so, als wäre er ein REST-Endpunkt, und führt während des CI-Builds eine Allowlist von Abfragen, die Einträge hinzufügen.
      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.
    • In GraphQL muss man Zugriffsrechte pro Attribut definieren oder die Abfragen vorab kompilieren und in eine Allowlist aufnehmen. Sonst leaken die Daten.
      https://hasura.io/docs/2.0/security/allow-list/
    • Jede brauchbare Third-Party-GraphQL-Bibliothek sollte in irgendeiner Form ACLs implementieren. Bei den beliebtesten scheint das auch so zu sein [1] [2].
      Eine einfache Idee ist, die Autorisierung im Datenmodell selbst umzusetzen. GraphQL delegiert dann get und list an 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...
    • Als ich HotChocolate benutzt habe, gab es dieses Problem nicht. Man kann Autorisierungsregeln sehr einfach an Entitäten oder Entitätseigenschaften hängen, und sie werden automatisch verarbeitet. Das gilt auch für Mutations.
  • Erstaunlich verantwortungsvolle und rücksichtsvolle Offenlegung

    • Waren in den Screenshots des Menüs „Discover profiles“ und der Like-Liste echte Profile enthalten? Falls ja, ist das trotz verpixelter Gesichter ziemlich verantwortungslos.
    • Das Verhalten passt nicht zu den Worten.
  • 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.

    • Als ich sie benutzt habe, war sie auch schon extrem schlecht. Wenn es nicht gerade seltsame Memory Leaks oder Datenschutzprobleme waren, dann war die UX einfach katastrophal umgesetzt.
      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.
    • Als ich sie benutzt habe, war die Community gut, aber die App war nie sauber entwickelt.
      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.