realm / realm-js

Realm is a mobile database: an alternative to SQLite & key-value stores
https://realm.io
Apache License 2.0
5.81k stars 577 forks source link

Realm Web: Persist and retrieve active users #2964

Closed kraenhansen closed 4 years ago

kraenhansen commented 4 years ago

Currently, when the web-browser is refreshed the currently logged-in user is forgotten. This needs to change by:

  1. Persisting the users access and refresh tokens in the browsers local-storage whenever these are known or gets updated.
  2. Retrieve stored credentials when the library gets loaded.
itwilson commented 4 years ago

This is key functionality to consider this a usable project for us. Is there a way to create a credentials object based on access token right now?

dalmo3 commented 4 years ago

Is it possible to retrieve anonymous users as well? Just started playing with realm-web on React and at each refresh a new set of profile/accessToken/refreshToken is created, absolutely cluttering localStorage.

I can see why creating a new anonymous user every time is expected behaviour. But what about cleanup? Calling logOut clears the tokens but not profile.

Edit: I just looked at the Stitch Browser SDK and initializeDefaultAppClient does actually use existing anonymous credentials from localStorage... is that possible with realm-web?

kneth commented 4 years ago

@dalmo3

I just looked at the Stitch Browser SDK and initializeDefaultAppClient does actually use existing anonymous credentials from localStorage... is that possible with realm-web?

Can I ask you to create a new issue for this? It's a bit easier to follow open issues and closed ones :smile:

niklasgrewe commented 3 years ago

@kraenhansen hi i am a newcomer of mongodb realm. I am using the realm web sdk for my svelte frontend application. Everthing is working fine at the moment, but isn't it insecure that the access and refresh tokens are stored in LocalStorage?

I read this from the realm docs

For web browsers, the JavaScript SDK stores these tokens in HTML5 local storage.

You can often read on the Internet that it is a security vulnerability. Is this also true for MongoDB Realm? Can the tokens theoretically be stolen and used elsewhere? Could you explain it?

kraenhansen commented 3 years ago

@niklasgrewe thanks for your interest in the project!

Local storage is a per origin key-value store, meaning the only JS code allowed access to the tokens are scripts loaded into the web application by the developer.

Would you mind sharing a link to an article outlining how this is insecure?

Can the tokens theoretically be stolen and used elsewhere?

Sure, if a developer is not careful choosing their dependencies, any piece of code running in the web app could steal the access and refresh token.

niklasgrewe commented 3 years ago

@kraenhansen thanks for your quick answer

Would you mind sharing a link to an article outlining how this is insecure?

  1. https://dev.to/rdegges/please-stop-using-local-storage-1i04
  2. https://blog.cotter.app/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end/

Sure, if a developer is not careful choosing their dependencies, any piece of code running in the web app could steal the access and refresh token

ok that's clear, but is there anything you can do with the stolen tokens? For example, can the attacker access data that the user has stored in MongoDB Atlas? Can he attack my MongoDB Cloud Instance in any way? Can he use the stolen tokens to access an api to get data from my cloud instance?

and one more question. The Realm Docs says:

The SDKs automatically take care of refreshing access tokens, so you do not need to worry about this when implementing client applications.

how long are the sessions valid? 30 days? in other words: When is the user automatically logged out and has to log in again?

kraenhansen commented 3 years ago

is there anything you can do with the stolen tokens?

The access token grants access to an app and data in the underlying MongoDB database. This access however is restricted to the rules defined by you as a developer: See https://docs.mongodb.com/realm/mongodb/define-roles-and-permissions/ for more information on this. The rules should be setup in a way that prevents malicious use of the database, since your users can't be trusted access to data that they don't own or manage (which all depends on your apps architecture).

The access token expires 30 minutes after it's created and the refresh token can be used to issue a new access token. I believe it expires after 30 days, this can be verified by obtaining a refresh token and decoding it's content. This limits the impact of an attack where an access token is leaked (in transit or via a XSS vulnerability). When logging out the refresh token and all access tokens it has issued are invalidated.

I've read both articles you mention and in principle I agree. It's a little more secure to store the tokens in a httpOnly cookie, since a compromised dependency won't be able to steal the token and send authorized requests from another machine. But, both articles assumes a XSS vulnerability or a malicious dependency and in that case the cookie approach would only be slightly more annoying for an attacker, which will still be able to make requests to the server on the user's behalf.

One though: We would have to find a solution for if we wanted to transition to cookies is how to handle the fact that multiple users can be authenticated in a Realm app at the same time. If the refresh token is stored in memory we would need to ensure it got namespaced with the users id and the user id was sent along in the request to create a new access token. How would the server otherwise know which of the multiple refresh token cookies to use / what user to send back an access token for.

Thanks again for bringing this to our attention! Security is paramount to the success of our users apps and therefore to our platform. I'll discuss this with the rest of the team to determine if implementing a cookie based approach is worth the tradeoff. I would like to reiterate however that there is in my opinion nothing inherently insecure about storing tokens in local storage. It does however allow attackers to steal and misuse the tokes if your web app has another XSS vulnerability, which is why it's always super important to avoid those.

Please feel free to open a new discussion on our developer community: https://community.mongodb.com There might be other users with similar concerns or other perspectives.

You're also welcome to open an issue on this repository requesting a feature of cookie-based storage of tokens.