Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sync protocol resistant to manipulations #86

Closed
palant opened this issue Mar 20, 2018 · 6 comments
Closed

Make sync protocol resistant to manipulations #86

palant opened this issue Mar 20, 2018 · 6 comments

Comments

@palant
Copy link
Owner

palant commented Mar 20, 2018

The sync protocol as implemented in #24 still has some issues. While the storage provider cannot decrypt the data stored by PfP, they might still be able to tamper with it:

  • Revert data to a previous revision, making all clients revert recent changes.
  • Remove all data from the file, making clients remove all their data as well.
  • Add bogus data to the file which will not decrypt but produce errors in PfP.

How this can be addressed:

  • A new syncRevision field is added to the data, defaulting to 0 if not set (data created by previous version). A sync client should always increase syncRevision when replacing the data. It should also store the highest syncRevision value it has seen and only perform sync operation if syncRevision increased. Seeing a lower syncRevision value should trigger a warning, the data has been tampered with.
  • There should also be a syncSignature field containing an HMAC-SHA256 signature. The data signed should be a normalized representation of the data without the syncSignature field but with syncRevision (stringified JSON without whitespace with keys sorted). Clients should always verify the signature before accepting the data, signature mismatch should trigger a warning that the data has been tampered with.
  • If a client performs the initial upload of the data (no file there yet), it should generate a random HMAC secret and store it encrypted in the data. If a client connects to storage and a file is there already, it should decrypt the HMAC secret there and use it to sign uploads in future. The HMAC secret should be stored unencrypted locally, the master password is only required for the initial sync.
  • Format version should increase to 3, so that older clients won't try to mess with newer data. Newer clients should accept both format version 2 and 3 for sync and backups.

There is still one legitimate scenario where the revision number might decrease: if the user removes the data from the storage and syncs an unrelated instance to it then. An existing client should refuse to sync then, there is no way to tell that it isn't an old version of the data. The user can disable sync and reconnect to repair this.

@palant palant changed the title Make sync protocol more resistant to manipulations Make sync protocol resistant to manipulations Mar 20, 2018
@palant
Copy link
Owner Author

palant commented Jun 2, 2019

Some additional considerations:

  • While JSON is an easy way to serialize data, it's also ambiguous and I'm not sure whether we can rely on the JSON serializer to be consistent across browsers. However, if we write our own serializer anyway it might be easier to use some simple binary format.
  • With the HMAC secret being random, there is a chance that two clients using the same master password will have different HMAC secrets (typically because data on the server was cleared and a new client connected then). It might be a good idea to derive HMAC secrets from the master password, then a signature mismatch can only be an incompatible upload (different master password) or data that has been tampered with.
  • If the client connects to the storage and finds incompatible data there, it should offer overwriting this data. Otherwise the only way of resolving this would be clearing the data on the server side, yet some storage providers (GDrive) make this fairly complicated while others (remoteStorage on 5apps) don't provide this functionality at all.

@palant
Copy link
Owner Author

palant commented Jun 2, 2019

It might be a good idea to derive HMAC secrets from the master password,

Never mind, this is a bad idea, as there is no salt which is random enough and could be used here. Then it just needs a way to resolve the conflict if it happens. Sync needs to be disabled on the failing client and the client reconnected then. With identical master passwords this will just work and bring the clients in sync. With different master passwords or otherwise broken data, connecting should error out and offer to remove the data.

@palant
Copy link
Owner Author

palant commented Jun 3, 2019

I'm not sure whether we can rely on the JSON serializer to be consistent across browsers.

The spec actually defines exactly which characters should be escaped and how. I tested this in Firefox and Chrome and it seems that we can rely on the results to be consistent. However, sorting keys is not possible.

So I think that in order to sign the data we should convert our data object to an array of key/value pairs, sorted by key (signature key excluded). So {foo: 1, bar: 2} becomes [["bar", 2], ["foo", 1]]. This array should then be stringified to JSON without any whitespace and signed.

palant added a commit that referenced this issue Jun 4, 2019
…hile keeping compatibility with format 2
@palant
Copy link
Owner Author

palant commented Jun 5, 2019

Initial upload requires the master password, which will become problematic if autolock delay is set to 0. As I realized now, this is already an issue due to required rekeying.

palant added a commit that referenced this issue Jun 5, 2019
@palant
Copy link
Owner Author

palant commented Jun 5, 2019

A bulk of this has been implemented, documentation has been updated as well. Better handling of edge conditions is still necessary.

@palant
Copy link
Owner Author

palant commented Jun 7, 2019

This can be considered resolved now, further UI enhancement is #103 now.

@palant palant closed this as completed Jun 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant