https://mjg59.dreamwidth.org/70061.html
Account name: [ ] Password [ ] [Log in]
(OpenID?) (Forgot it?) [ ] Remember Me
You're viewing [personal profile] mjg59's journal
Create a Dreamwidth Account Learn More
[ ] [Interest ] [Go]
Reload page in style: site light
Matthew Garrett
Client-side filtering of private data is a bad idea
Client-side filtering of private data is a bad idea
Aug. 19th, 2024 11:11 am
[personal profile] mjg59
(The issues described in this post have been fixed, I have not
exhaustively researched whether any other issues exist)
Feeld is a dating app aimed largely at alternative relationship
communities (think "classier Fetlife" for the most part), so
unsurprisingly it's fairly popular in San Francisco. Their website
makes the claim:
`Can people see what or who I'm looking for?
No. You're the only person who can see which genders or sexualities
you're looking for. Your curiosity and privacy are always protected.'
which is based on you being able to restrict searches to people of
specific genders, sexualities, or relationship situations. This sort
of claim is one of those things that just sits in the back of my head
worrying me, so I checked it out.
First step was to grab a copy of the Android APK (there are multiple
sites that scrape them from the Play Store) and run it through
apk-mitm - Android apps by default don't trust any additional
certificates in the device certificate store, and also frequently
implement certificate pinning. apk-mitm pulls apart the apk, looks
for known http libraries, disables pinning, and sets the appropriate
manifest options for the app to trust additional certificates. Then I
set up mitmproxy, installed the cert on a test phone, and installed
the app. Now I was ready to start.
What became immediately clear was that the app was using graphql to
query. What was a little more surprising is that it appears to have
been implemented such that there's no server state - when browsing
profiles, the client requests a batch of profiles along with a list
of profiles that the client has already seen. This has the advantage
that the server doesn't need to keep track of a session, but also
means that queries just keep getting larger and larger the more you
swipe. I'm not a web developer, I have absolutely no idea what the
tradeoffs are here, so I point this out as a point of interest rather
than anything else.
Anyway. For people unfamiliar with graphql, it's basically a way to
query a database and define the set of fields you want returned.
Let's take the example of requesting a user's profile. You'd provide
the profile ID in question, and request their bio, age, rough
distance, status, photos, and other bits of data that the client
should show. So far so good. But what happens if we request other
data?
graphql supports introspection to request a copy of the database
schema, but this feature is optional and was disabled in this case.
Could I find this data anywhere else? Pulling apart the apk revealed
that it's a React Native app, so effectively a framework for allowing
writing of native apps in Javascript. Sometimes you'll be lucky and
find the actual Javascript source there, but these days it's more
common to find Hermes blobs. Fortunately hermes-dec exists and does a
decent job of recovering something that approximates the original
input, and from this I was able to find various lists of database
fields.
So, remember that original FAQ statement, that your desires would
never be shown to anyone else? One of the fields mentioned in the app
was "lookingFor", a field that wasn't present in the default profile
query. What happens if we perform the incredibly complicated hack of
exporting a profile query as a curl statement, add "lookingFor" into
the set of requested fields, and run it?
Oops.
So, point 1 is that you can't simply protect data by having your
client not ask for it - private data must never be released. But
there was a whole separate class of issue that was an even more
obvious issue.
Looking more closely at the profile data returned, I noticed that
there were fields there that weren't being displayed in the UI. Those
included things like "ageRange", the range of ages that the profile
owner was interested in, and also whether the profile owner had
already "liked" or "disliked" your profile (which means a bunch of
the profiles you see may already have turned you down, but the app
simply didn't show that). This isn't ideal, but what was more
concerning was that profiles that were flagged as hidden were still
being sent to the app and then just not displayed to the user.
Another example of this is that the app supports associating your
profile with profiles belonging to partners - if one of those
profiles was then hidden, the app would stop showing the partnership,
but was still providing the profile ID in the query response and
querying that ID would still show the hidden profile contents.
Reporting this was inconvenient. There was no security contact listed
on the website or in the app. I ended up finding Feeld's head of
trust and safety on Linkedin, paying for a month of Linkedin Pro, and
messaging them that way. I was then directed towards a HackerOne
program with a link to terms and conditions that 404ed, and it took a
while to convince them I was uninterested in signing up to a program
without explicit terms and conditions. Finally I was just asked to
email security@, and successfully got in touch. I heard nothing back,
but after prompting was told that the issues were fixed - I then
looked some more, found another example of the same sort of issue,
and eventually that was fixed as well. I've now been informed that
work has been done to ensure that this entire class of issue has been
dealt with, but I haven't done any significant amount of work to
ensure that that's the case.
You can't trust clients. You can't give them information and assume
they'll never show it to anyone. You can't put private data in a
database with no additional acls and just rely on nobody ever asking
for it. You also can't find a single instance of this sort of issue
and fix it without verifying that there aren't other examples of the
same class. I'm glad that Feeld engaged with me earnestly and fixed
these issues, and I really do hope that this has altered their
development model such that it's not something that comes up again in
future.
(Edit to add: as far as I can tell, pictures tagged as "private"
which are only supposed to be visible if there's a match were
appropriately protected, and while there is a "location" field that
contains latitude and longitude this appears to only return 0 rather
than leaking precise location. I also saw no evidence that email
addresses, real names, or any billing data was leaked in any way)
* Previous Entry
* Add Memory
* Share This Entry
* Next Entry
---------------------------------------------------------------------
* 2 comments
* Reply
---------------------------------------------------------------------
Flat | Top-Level Comments Only
no subject
Date: 2024-08-20 10:04 am (UTC)
From: (Anonymous)
You should ask them to pay for the Linkedin Pro
* Link
* Reply
* Thread
* Hide 1 comment
* Show 1 comment
no subject
Date: 2024-08-20 05:41 pm (UTC)
From: (Anonymous)
Yeah, lol. You just saved them from a very very big PR problem and it
would be nice if they could show a little bit of gratitude. Though,
good on you for doing this for the betterment of everyone.
* Link
* Reply
* Thread from start
* Parent
* Previous Entry
* Add Memory
* Share This Entry
* Next Entry
* 2 comments
* Reply
Flat | Top-Level Comments Only
Profile
Matthew Garrett
About Matthew
Power management, mobile and firmware developer on Linux. Security
developer at Aurora. Ex-biologist. [personal profile] mjg59 on
Twitter. Content here should not be interpreted as the opinion of my
employer. Also on Mastodon.
Page Summary
* (Anonymous) - (no subject)
Expand Cut Tags
No cut tags
Top of page