cubos / sdkgen

[ DEPRECATED, SEE https://github.com/sdkgen/sdkgen ] Tool that aims on solving client-server communication and data layout sharing between server, web, android and ios using a description language also called sdkgen.
MIT License
45 stars 9 forks source link

RFC: About Devices, Sessions and Authentication #7

Open lbguilherme opened 6 years ago

lbguilherme commented 6 years ago

Currently each connected client is device, that has an ID and is saved in the database and is exposed as ctx.device. The client holds a device token. Session is done by saving some data on the devices table.

Problems:

  1. There is no way to get an history previous sessions of a device.
  2. If the device token is leaked, then a future authentication of that device will be leaked as well. This breaks "Backward Secrecy".
  3. It is hard to attach actions to a particular session of a specific user on a particular device, for auditing.

Also, the device ID is not always persisted when the target app is removed and then reinstalled, which creates two devices for the same physical device. Currently this is not done because uninstalling and reinstalling an app (or cleaning data) should also logout the user. As the user is attached to our device, we end up removing the whole device by losing the device token on device. It also makes it hard to black list a device.


Solution:

  1. Do a best effort to store the device token on the device using permanent storage. A cryptographic secure vault if possible. (This is doable on iOS and Android. TODO: Investigate about what is the best effort for web @dygufa @vhfmag)
  2. Create the concept of device stored data:

Device-stored Data:

Any api call can send to the device data to be stored, this can be session tokens, authentication info, list of permissions, anything relevant. Before sending, this chunk of data will be JSON encoded, then encrypted and then signed by the server with a device specific key (this is pretty much JWT). The receiver device won't be able to read or modify the information, the only thing it can possibly do is either store it or destroy it. It also can't be transferred to another device even if leaked, it is linked to the device token, that is stored in some safer way.

The device should store it in a way that if the user want to clear all data, it will be removed as well (localStorage, SharedPreferences, ...). This should be sent on every request to the sever.

Upon receiving, the server will decrypt the information and verify the signature. If it doesn't match, simply discard and act as if nothing was sent.

For the implementation of an api function, the data will be available as ctx.data. It can be modified directly and after the function returns, the modified version will be encrypted, signed and sent back alongside the usual response. It is by default an empty object {}.

This enforces that device has no piece of information that sdkgen is not aware about.

For backward compatibility with clients that are in production and aren't aware of this data, we can store it in the database and load/store ourselves.


With these two features it is possible to implement the concept of sessions without special support from sdkgen. An implementation can have a table of sessions attaching an user to a device. The id of the session can be saved on ctx.data.sessionId (it doesn't need to be a cryptographic-secure token or anything special).

This also doesn't touch on authentication itself. The implementation can still validate who is who by any means. Any function can read and modify a device's data.

What do you think? @dygufa @davidcpires @vhfmag @tironiigor

dygufa commented 6 years ago

First, I can't see a better option than storing the "bearer token" on localstorage for the web env.

Fot the sessions thing I think we should create the concept of middlewares. Using that concept we can create a "session middleware" to read requests, make any database interactions and modify the "context" with session info.

lbguilherme commented 6 years ago

Fot the sessions thing I think we should create the concept of middlewares. Using that concept we can create a "session middleware" to read requests, make any database interactions and modify the "context" with session info.

I like it. But suppose there is a middleware that verifies the session and populates the "currentUser" field, and throws if there is no logged in user. How to specify that a certain function need to skip this middleware (because it doesn't expect the user to be logged in)?