oxidecomputer / omicron

Omicron: Oxide control plane
Mozilla Public License 2.0
250 stars 39 forks source link

information leak as a result of the way resource lookups work #665

Open davepacheco opened 2 years ago

davepacheco commented 2 years ago

I think an unauthorized user could discover whether an Organization "o1" exists by attempting to lookup a project "p1" inside it. You'll get back a 404 no matter what. If "o1" exists, the 404 will say that p1 doesn't exist. If "o1" doesn't exist, the 404 will say that o1 doesn't exist. In an ideal world, if you had access to see that "o1" existed, we'd tell you it was "p1" that didn't exist; otherwise, we'd tell you that "o1" doesn't exist.

The problem: it's hard for us to know whether you should be able to see "o1". The rule we currently use is: you can see an Organization "o1" if you have permissions to see or do anything with something inside o1. That way, if you want to share, say, o1/p1/i1 with some other user, you don't also have to remember to share o1/p1 or o1 with them. (An alternative would be to require you to share o1 and p1 with them, but have the API do that automatically. That seems to get hairy: what if i1 moves to another Project or Organization? Do we also revoke any automatically-created roles for you? At that point, isn't this just the same rule we're using, implemented using database denormalization?)

A consequence of this: it's prohibitive to answer the question "can user X see Organization Y" -- we have to either enumerate all the resources they have access to and see if they're in that Organization, or we have to enumerate all the resources in the Organization and see if they have access to them. Both of these are potentially huge quantities.

One way to solve this would be to have the 404 always report the complete path that you looked up. Arguably at that point, the error message is useless anyway, so we could just have it be something generic like "resource does not exist". But it does feel like we're throwing away potentially useful information there.

david-crespo commented 2 years ago

Giving no info is a very simple solution. If someone is trying to debug why /organizations/my-org/projects/my-project/vpcs/my-vpc is 404ing, they can easily try /organizations/my-org/projects/my-project and /organizations/my-org. Plus, if I got the message project not found I would not necessarily be confident it meant the org existed, and I would probably try the org request anyway.

jessfraz commented 2 years ago

In the ideal world though, if a user lands on something they can't see they should be able to request permission just like with a google doc.

I may be wrong, and correct me if so, but I Don't understand the issue in people knowing X name exists it doesn't matter unless we have a vuln somewhere else where by just knowing the name grants you access. So I don't really understand the problem in making a nicer user experience by throwing up a screen like google docs does to allow requesting access

jessfraz commented 2 years ago

in meetings with potential customers everyone loved this idea fwiw.

jessfraz commented 2 years ago

this way if so and so shares a link with you to something and you don't have access they don't have to figure out the right concoction of permissions to add so you can do the thing, you just hit request, they accept and boom, the concoction of permissions has been added to you, versus the operator becoming so frustrated that the person keeps telling them they cant see X that they just allow all permissions and then one day those credentials leak and everything is exposed versus just that one effing thing they wanted to see

TLDR: this is a feature not a bug

jessfraz commented 2 years ago

so I'd do the foollowing, if the user is not authed like there is no token or anything, obviously 404

if the user is authed and they are a member of the same silo as the thing, show the google docs request access button

jessfraz commented 2 years ago

you can determine the 40x statuses you want but id return 404 for unauthed or known users in a different silo

davepacheco commented 2 years ago

Yeah, I can definitely see the convenience of the way Google Drive does this. It's a critical difference though that as far as I know, Google Drive URLs are unique and not really guessable. The only plausible way that you can have a link to a specific document is that the link came from somebody who was authorized to see it. Thus, you know it exists. So it's pretty unlikely that Google is leaking information to you by offering to ask the owner for permission.

That's not true for our API. If you get a 403 accessing /organizations/human-resources/projects/2022-02-03-layoffs, then you know that the "human-resources" org exists and the "2022-02-03-layoffs" project exists -- clearly information that the owner might not want you to know.

In this way I think we're more like the GitHub API, which sends 404s when you attempt to access something you're not supposed to see because you can totally learn useful information if you know that, say, "oxidecomputer" has a clone of some well-known repo.

I wonder if we can have the best of both worlds: what if we send a 404, but the console shows a page saying "Either this resource doesn't exist or you don't have access to view it. Click here to request access if resource exists." This sounds a little goofy, but a lot of web sites do this with password reset screens because they don't want to leak whether someone has an account there.


so I'd do the foollowing, if the user is not authed like there is no token or anything, obviously 404

I believe that case is supposed to be a 401 with a suitable WWW-authenticate header.

if the user is authed and they are a member of the same silo as the thing, show the google docs request access button

Based on the current plan for Silos (which I'm still in the process of writing up in RFD 234), you won't even be able to ask for something that's not in your Silo. All URLs are interpreted as within the Silo that's associated with your credential.


Background: In general I believe it's considered an important security practice to return 404 for objects that a user cannot read to avoid leaking information about their existence. Auth0 talks about this in their discussion of HTTP status codes. Oso's Authorization Academy says:

"The default strategy for handling an authorization failure is to return an HTTP 403 Forbidden message, along with any details that might be helpful for the client. However, in some cases returning an error message would be revealing information that the user should not otherwise know. For example, suppose a GitClub user visits /org/acme/repo/secret_project – a private repository – then a 403 Forbidden message might reveal to the user that such a repository exists. Therefore, it is best practice to return an HTTP 404 NotFound message whenever the user is not even allowed to read the resource, regardless of what action they are attempting."

I found lots of other posts about this too.

But if we provide a link to "request access" and make clear that it does nothing if the resource really doesn't exist, we're not leaking information and it's still convenient.

jessfraz commented 2 years ago

I'm fine with request access if it exists. But I still don't see the harm in knowing something exists. And yes I know all the specs say not to do this but I still challenge with "who cares?" in that show me an example of an exploit without another exploit where purely knowing the name alone allowed access to something that person should not have had access to.

jessfraz commented 2 years ago

you could also claim that someone could brute force the google docs id by trying every single possible combination, sure its a lot but there's people trying to find sha collisions so ... yeah, I still think its a dumb and weird thing where knowing something exists is bad and I don't understand why.

jessfraz commented 2 years ago

what would be really freaking ncie is if the API errored with a 40x but said go to X URL to request access if the user was in the same silo

jessfraz commented 2 years ago

And like to put your mind at ease we are still following the 404 guidelines for unauthenticated users (people who ping an endpoint w no auth or bad credentials that don’t work for a real usr / service account) and for people outside the silo.

Right, but we are just giving users in the same silo a better experience by messaging them they can request access to the thing they are trying to do. Which in turn I think everyone would rather people in their silo know something exists but potentially lack access to it then some operator giving user X all permissions since they can’t figure out the right jenga combination of permission to allow access to one specific thing.

Happens all the time and this is why shit is in the news when some company was hacked on the cloud.

On Feb 2, 2022, at 8:37 PM, Jess Frazelle @.***> wrote:

 what would be really freaking ncie is if the API errored with a 40x but said go to X URL to request access if the user was in the same silo

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.

davepacheco commented 2 years ago

But I still don't see the harm in knowing something exists. And yes I know all the specs say not to do this but I still challenge with "who cares?" in that show me an example of an exploit without another exploit where purely knowing the name alone allowed access to something that person should not have had access to.

I think the example I gave shows pretty compellingly how information can be leaked without another exploit. Even so, I'm not sure why that matters. This is the point of defense in depth. Multiple exploits do happen.

You could also claim that someone could brute force the google docs id by trying every single possible combination

It looks like people have estimated that to be impossible. That's the critical difference here. Resource names are not remotely random enough to make the same claim about them.

Which in turn I think everyone would rather people in their silo know something exists but potentially lack access to it then some operator giving user X all permissions since they can’t figure out the right jenga combination of permission to allow access to one specific thing.

Agreed that it's better to have an IAM system that causes people to give fine-grained access to exactly who needs it rather than causing them to throw their hands in the air and open things up. And yes, the latter is a real risk. There are a range of mitigations that can help this. For example, we can provide a static set of roles that correspond with real use cases (rather than a huge list of fine-grained permissions), similar to the way Google Docs has a "reader" role. I don't think people usually have the problem of not knowing which role to grant somebody to let them view a Google Doc. Another mitigation for the problem you mentioned is that we can give users by default a role that allows them to see whether things exist [within their Silo]. Then they won't get the 404 at all -- they'll get the 403 if they try to do something they're not allowed to do. (A 403 can always have the "request access" button.) Doing it that way, if an administrator does want to hide that something exists, they can change the way that role gets assigned.

To be clear, it's not important to me whether users can see everything by default. It's just that if we want that behavior, I think we should express that as "you [automatically?] get the roles that grant you the permissions to see it" because that makes both use cases possible. If we decree that you can always see everything, then if somebody wants something private, they can't have it.

I'm fine with request access if it exists.

Sounds good!

jessfraz commented 2 years ago

Yeah I mean I get the layoffs thing but if you knew that someone might find out it exists you’d probably name it “butts” instead or anything else. I think the harm comes from people not realizing it would be exposed.

In the same sense personally I’d love it if when people who are members of our GitHub org didn’t have access to a GitHub repo could request access to it just by going to the link. Obviously not how it works today and if we had a repo named fire-X we wouldn’t want that but I’m just saying if we knew that’s how it worked we’d obviously never do that.

On the other side of it, think of all the funny shit people would sit on just so people wonder wtf is inside of it.

On Feb 2, 2022, at 9:26 PM, David Pacheco @.***> wrote:

 But I still don't see the harm in knowing something exists. And yes I know all the specs say not to do this but I still challenge with "who cares?" in that show me an example of an exploit without another exploit where purely knowing the name alone allowed access to something that person should not have had access to.

I think the example I gave shows pretty compellingly how information can be leaked without another exploit. Even so, I'm not sure why that matters. This is the point of defense in depth. Multiple exploits do happen.

You could also claim that someone could brute force the google docs id by trying every single possible combination

It looks like people have estimated that to be impossible. That's the critical difference here. Resource names are not remotely random enough to make the same claim about them.

Which in turn I think everyone would rather people in their silo know something exists but potentially lack access to it then some operator giving user X all permissions since they can’t figure out the right jenga combination of permission to allow access to one specific thing.

Agreed that it's better to have an IAM system that causes people to give fine-grained access to exactly who needs it rather than causing them to throw their hands in the air and open things up. And yes, the latter is a real risk. There are a range of mitigations that can help this. For example, we can provide a static set of roles that correspond with real use cases (rather than a huge list of fine-grained permissions), similar to the way Google Docs has a "reader" role. I don't think people usually have the problem of not knowing which role to grant somebody to let them view a Google Doc. Another mitigation for the problem you mentioned is that we can give users by default a role that allows them to see whether things exist [within their Silo]. Then they won't get the 404 at all -- they'll get the 403 if they try to do something they're not allowed to do. (A 403 can always have the "request access" button.) Doing it that way, if an administrator does want to hide that something exists, they can change the way that role gets assigned.

To be clear, it's not important to me whether users can see everything by default. It's just that if we want that behavior, I think we should express that as "you [automatically?] get the roles that grant you the permissions to see it" because that makes both use cases possible. If we decree that you can always see everything, then if somebody wants something private, they can't have it.

I'm fine with request access if it exists.

Sounds good!

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.

jessfraz commented 2 years ago

Also I like the idea of the role by default. Where someone can turn it off if they do ever create some sketchy project they want no one to know about

On Feb 2, 2022, at 9:32 PM, Jess Frazelle @.***> wrote:

 Yeah I mean I get the layoffs thing but if you knew that someone might find out it exists you’d probably name it “butts” instead or anything else. I think the harm comes from people not realizing it would be exposed.

In the same sense personally I’d love it if when people who are members of our GitHub org didn’t have access to a GitHub repo could request access to it just by going to the link. Obviously not how it works today and if we had a repo named fire-X we wouldn’t want that but I’m just saying if we knew that’s how it worked we’d obviously never do that.

On the other side of it, think of all the funny shit people would sit on just so people wonder wtf is inside of it.

On Feb 2, 2022, at 9:26 PM, David Pacheco @.***> wrote:

 But I still don't see the harm in knowing something exists. And yes I know all the specs say not to do this but I still challenge with "who cares?" in that show me an example of an exploit without another exploit where purely knowing the name alone allowed access to something that person should not have had access to.

I think the example I gave shows pretty compellingly how information can be leaked without another exploit. Even so, I'm not sure why that matters. This is the point of defense in depth. Multiple exploits do happen.

You could also claim that someone could brute force the google docs id by trying every single possible combination

It looks like people have estimated that to be impossible. That's the critical difference here. Resource names are not remotely random enough to make the same claim about them.

Which in turn I think everyone would rather people in their silo know something exists but potentially lack access to it then some operator giving user X all permissions since they can’t figure out the right jenga combination of permission to allow access to one specific thing.

Agreed that it's better to have an IAM system that causes people to give fine-grained access to exactly who needs it rather than causing them to throw their hands in the air and open things up. And yes, the latter is a real risk. There are a range of mitigations that can help this. For example, we can provide a static set of roles that correspond with real use cases (rather than a huge list of fine-grained permissions), similar to the way Google Docs has a "reader" role. I don't think people usually have the problem of not knowing which role to grant somebody to let them view a Google Doc. Another mitigation for the problem you mentioned is that we can give users by default a role that allows them to see whether things exist [within their Silo]. Then they won't get the 404 at all -- they'll get the 403 if they try to do something they're not allowed to do. (A 403 can always have the "request access" button.) Doing it that way, if an administrator does want to hide that something exists, they can change the way that role gets assigned.

To be clear, it's not important to me whether users can see everything by default. It's just that if we want that behavior, I think we should express that as "you [automatically?] get the roles that grant you the permissions to see it" because that makes both use cases possible. If we decree that you can always see everything, then if somebody wants something private, they can't have it.

I'm fine with request access if it exists.

Sounds good!

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.