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

Improve multi-tenant security #8260

Open
ricardopieper opened this issue Sep 25, 2024 · 1 comment
Open

Improve multi-tenant security #8260

ricardopieper opened this issue Sep 25, 2024 · 1 comment
Assignees

Comments

@ricardopieper
Copy link

Describe the feature request

I wish the frontend SDKs were not be able to change their context at will.
Or make it clear in the docs when you cannot use the client SDKs.

Background

Hello, we are studying whether we will adopt Unleash or not in our application.

We have a multi-tenant application, where tenants cannot see the data of another tenant in any way. This includes the feature toggle state.

We use the feature toggles both in our backend and frontend. The backend uses toggles to change the way we do certain things, while in the frontend we use it to conditionally render things. So we don't do anything crazy with it.

Our customers are very sensitive to security breaches (most of them are banking/finance) and we are under constant scrutiny from red teams, both our own and from our customers.

The docs suggest this is the way to segment users by tenant using the SDK:

const unleash = new UnleashClient({
    url: 'https://<your-unleash-instance>/api/frontend',
    clientKey: '<your-client-side-token>',
    appName: 'my-webapp',
});

//...

unleash.setContextField('tenantId', 'SomeTenantId');

In this case, client is in complete control of their own segmentation. We consider it to be a data breach if the user of tenant X can successfully check if another tenant has some feature enabled.

Our in-house feature toggle system today is very bad, but it is secure: the toggle state of one tenant never leaks to another tenant.

One way is to use an unguessable tenant ID but then it becomes more cumbersome to handle things in the UI.

The way I see it, the only way to use Unleash for us is to do the entire thing in our backend, and expose a route that the frontend clients can use to check that a certain feature toggle is enabled.

Am I missing something in the docs that addresses this or should we just do everything in the backend?

Solution suggestions

I didn't think too hard about it, so I don't know if they make sense or not.

Solution 1: Per-Tenant clientKey:

The SDK could be initialized with a different clientKey for each tenant. Using the unleash API, we could associate a client key with certain context properties that cannot be overwritten by the client. The app backend must return an appropriate clientKey for the frontend to initialize the client.

Solution 2: Predefined contexts identified by a key:

A separate unguessable key that you use to initialize the client. In Unleash, you define these keys and their context. Again the app backend is responsible for returning this key.

const unleash = new UnleashClient({
url: 'https:///api/frontend',
clientKey: '',
predefinedContextKey: await getUnleashPredefinedContextKey(), //does a request to the backend app
appName: 'my-webapp',
});

Maybe there are other solutions potentially leveraging Unleash Edge, but I can't think of one ATM.

@chriswk chriswk self-assigned this Sep 26, 2024
@ivarconr
Copy link
Member

Hi @ricardopieper,

thanks for reaching out. You did not mention which SDK you are leveraging, but based on your description I assume you are using a frontend SDK, and particular the JavaScript version.

First I want to stress that your entire frontend application is exposed as it already runs in the context of the user. You should not think of feature flags as a security / permission systems, and you should generally protect your data in the back-end.

The example on how to set the tenant context makes sense for a server-side application, where your control the code, and it is not exposed. I somewhat agree it to some degree is a bit unfortunate to expose the tenantId, if that allow you to identify customers, but again, a feature flag or knowing another tentantId should not enable access to actual customer data.

A simple solution right now would be to leverage ungessable tenantId thorugh a simple hashing function and define all possible tenantIds in Unleash as legal values on the context field.

This way you do not have to change your application logic, you can simply do:
unleash.setContextField('tenantId', sha256('SomeTenantId'));

And in the UI you can select the tenant you are targeting, where you have pre-populated the possible value with a human readable display value, making it easier to work with.

I hope that helps!

(This being said, we have a discovery item in our roadmap to add a "contextEnricher" capability to edge, where you should be able to enrich the context on the edge side, e.g. automatically adding correct tenantId. Doing it server-side allows you to control the logic and avoid the need to trust the client).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: For later
Development

No branches or pull requests

3 participants