vexl-it / vexl

Vexl app
https://vexl.it
GNU General Public License v3.0
63 stars 12 forks source link

Discovery: anonymization of FCM tokens to prevent grouping inboxes by owner #656

Closed kaladivo closed 1 month ago

kaladivo commented 9 months ago

Current problem

We need to push messages to the device for core features to work. The most important features are:

Core of the problem

We use firebase messaging service (FCM) to issue push notifications (FCM is Android Native & uses APNs- Apple Push Notifications Service - for iOS). Notifications are issued from server. For server to issue push notification using FCM we need the following:

For each user, notification tokens need to be stored in database, in our model we store them in 2 places

Our aim is to make inboxes anonymous and make it impossible to link multiple inboxes to one user. Currently it is possible to do that using fcm token.

Main constraint in this regard is the sending of push notifications. Server needs to handle the notification payload - which is encrypted - and notification token to to FCM.

Currently there are following informations sent with a chat notification:

Encrypting FCM - Possible solution that still utilises FCM (and APNS on iOS)

We need to find a way how to prevent linking multiple inboxes to one user. There are following constraints that the solution needs to meet:

The token in chat database can be Symmetrically encrypted with a secret. For every inbox, client will encrypt the fcm token with symmetric key and send it to the server. Server will store it with other inbox metadata. Created inbox should be stored as follows:

Client side (inbox owner):

Server side:

When another client wants to send notification to the client, he first needs have the cypher key. Which he will send to the server together with payload which will server use to decrypt the FCM token cypher and issue the notification. Cypher key can be included in public payload of the offer.

The problem here is, that eventually server needs to have plain FCM Token and target inbox public key to send the notification. This still makes it possible for server to group inboxes by fcm token (albeit it is more complicated since it can't be done from the database data).

The way how to solve this is removing public keys from notification payload.

Messaging connections not inboxes (PoW draft, this needs to be refined further)

Each connection represents open channel. There is no information about public keys associated with connection. This is rough connection shape stored in database (admin id can be replaced by mor sophisticated signature system):

Sending messages A -> B:

Opening connection A -> B: TODO

Alternate solution - ditching FCM messaging all together

Basically, instead of using APNS we can open a socket and have server push messages though. This is very straightforward to do on android using foreground services.

On iOs this is problematic.

It currently seems there is no way to keep socket connection active (or at least have the app react to incoming messages).

From old ios 4 documentation:

kaladivo commented 8 months ago

Final solution

This is not a proposal to rewrite of chat microservice! This is just a way how to remove FCM tokens to inboxes table from the database.

It is possible to implemented and release this solution without breaking compatibility to previous versions!

Overview

FCM token will be encrypted and stored into offer's public payload using ECIES with server public key. To send chat message, 2 operations should be done - ideally separated so they can not be linked:

  1. Issue notification to receiver
  2. Send encrypted message to server

Providing FCM token to other clients

  1. Get server public key (either from build time constant or by http get)
  2. ECIES encrypt local FCM token using server public key
  3. Add cipher text to offer public payload
  4. Treat FCM token update as offer update (just reupload public payload)

Updating FCM token in open chats

This needs o be done since chats are only "weakly" linked to offers. Offer for chat can already be removed.

Sender

  1. Creates token ciphertext
  2. Sends chat message with updated cipher text to all open chats

Reciever

  1. Recieves update
  2. Updates fcm token cipher text for the chat

Issuing notification to receiver

Client sender:

  1. Get FCM token cipher text from public payload of the offer
  2. Encrypt notification payload and send POST with {"notificationPayload": cypherText, "fcmcipher": fcmTokenCypherText} - Notification payload should be treated at potentially dangerous, there is no validation that the data are from verified author

Server:

  1. Decrypt cypher into FCM token and issue notification with provided payload + fcm token ciphertext. Server should not recieve any other information about the message.

Client receiver:

  1. Receive FCM message with payload
  2. Find inbox keypair by matching fcmcipher in notification payload with fcmcipher in published offers.
  3. (Decrypt encrypted payload with private key - Notification payload should be treated at potentially dangerous, there is no validation that the data are from verified author.)
  4. Fetch messages for the inbox.
  5. Display notification

Sending encrypted message to server

Sending / receiving messages is beyond scope of this change set. This is just a simplified description of how it it's currently done.

Client sender:

  1. Encrypt message
  2. Call http post with: a. Encrypted payload b. Validated public key of sender

Server:

  1. Validate public key of sender
  2. Save encrypted message to db
  3. (Ideally remove messages after set amount of time has passed #301)
  4. ! Do not send notification if sender client indicates that it is capable of calling notification microservice (in client-version header)!

Client receiver:

  1. Call get messages for public key
  2. decipher message payload
  3. Call remove seen messages to clear from server

Caveats

Questions

Proposed changes to be made

See list of tickets in here: https://github.com/vexl-it/vexl/milestone/10

kaladivo commented 8 months ago