nodeSolidServer / solid-auth-client

A browser library for performing authenticated requests to Solid pods
https://solid.github.io/solid-auth-client/
MIT License
95 stars 42 forks source link

Local storage is insecure #109

Open mrkvon opened 5 years ago

mrkvon commented 5 years ago

Local Storage is insecure and shouldn't be used for storing sensitive information. Storing authentication info (e.g. oidc.session.privateKey here) in local storage is not acceptable in production environment. The above linked OWASP document suggests alternatives.

RubenVerborgh commented 5 years ago

Thanks @mrkvon, this indeed has been a concern for some time.

@dmitrizagidulin Does this invalidate the entire idea of PoPtokens? We use PoPtokens to avoid extra requests to the IDP, but the good thing is that those requests can only be made by one origin. With PoPtokens, tokens for any domain can be generated anywhere by anyone who steals local storage. Not having PoPtokens would reduce the attack surface, it seems.

mrkvon commented 5 years ago

Disclaimer: I don't understand details of OIDC or WebId-OIDC.

Is it not possible to use http-only cookies or some other storage mechanism that can be considered secure?

RubenVerborgh commented 5 years ago

Is it not possible to use http-only cookies

No, the client needs access to the tokens to make authenticated requests.

or some other storage mechanism

That might be possible, but OWASP is very liberal in what they consider threats, as it includes cross-site scripting (which lets you get away with more or less everything). Having short-lived tokens is important.

mrkvon commented 5 years ago

@RubenVerborgh thank you for explaining!

If I understand well: After the user gets authenticated with the identity provider, they receive some kind of token which they're supposed to use to authenticate themselves with various solid pods. They need to use JavaScript for this.

Indeed, AFAIK, using 3rd party scripts to steal or manipulate the local storage is its main security issue (includes XSS, but also just using any 3rd party library). Therefore any storage that is accessible by JavaScript is vulnerable in the same way, isn't it?

Feeling stuck.

RubenVerborgh commented 5 years ago

Therefore any storage that is accessible by JavaScript is vulnerable in the same way, isn't it?

It depends. I have an idea in the back of my mind, where the local storage is encrypted, and the key to that encryption is only known by a background worker. That background worker can only run on certain domain, so keys cannot be stolen.

Cross-site scripting might then still make unauthorized requests, but that is hard to stop in the first place.

dmitrizagidulin commented 5 years ago

Just saw this issue.

Basically, it's just as @RubenVerborgh said.

There are no authentication methods available in the browser that are not vulnerable to Cross Site Scripting attacks. Local storage (where the PoP session tokens are stored) is vulnerable. But so are cookies. And so is WebID-TLS (browser certificates).

So, as such, PoP tokens are no more vulnerable than any other authentication mechanism.

Basically, if a hostile script is injected into the page (the kind that has access to local storage), it can make any sort of request it wants, regardless of authentication method, since it can get access to the auth client itself.

That said, there are steps we can take to mitigate this threat. But there's basically only a handful of strategies available (several of which are outlined in the Threat: Obtaining Access Tokens section of the OAuth2 Threat and Security Model document:

dmitrizagidulin commented 5 years ago

@RubenVerborgh

PoPtokens, tokens for any domain can be generated anywhere by anyone who steals local storage. Not having PoPtokens would reduce the attack surface, it seems.

Not quite. PoP tokens have an ID token embedded in them, that has a limited lifetime (it expires when the session expires). And those ID tokens are only issued to one particular domain (enforced by redirect_uri restrictions). So, basically, PoP tokens have the same attack surface as do regular OAuth2 ID and access tokens.

mrkvon commented 5 years ago

@RubenVerborgh Thank you for sharing your idea. I still try to understand it. If it works, why don't we just store the sensitive data directly in web worker? What is the difference between keeping the encryption key and the data themselves with the web worker? (I have only just started learning about web workers.)

@dmitrizagidulin When XSS takes place, the attacker can do any actions they defined. However, with http-only cookies the stored keys don't get exposed to them and can't be edited by them. In this sense local storage and http-only cookies are not equal. Is there an issue in my reasoning?

Further thoughts

The http-only cookies can be sent to one domain only. That's why we have hard time using them to authenticate in a distributed system, is that right?

Would the following conversation between client, identity provider and data server be feasible to solve the issue?

Let's assume client has set a http-only cookie from identity provider.

This assumes that identity provider has a memory.


If this is diverging too much, is there a better place for the discussion?

RubenVerborgh commented 5 years ago

@dmitrizagidulin

Auth token scope should be limited wherever possible (this is where Origin-based access controls comes in -- there is some work to be done in this area)

And those ID tokens are only issued to one particular domain (enforced by redirect_uri restrictions).

Those restrictions only work in the browser. If an attacker steals localStorage, they can send its contents to a server, which can fake any Origin header, thus removing the domain-based protection. That's why I argue the attack surface is broader: steal one set of tokens, and have access to any server.

Limit token lifetime

That seems one of the most important mechanisms.

Additionally, encrypting localStorage with a key that only can be obtained from the Origin with a secret (HTTP-only) cookie, is something we should explore.

RubenVerborgh commented 5 years ago

Additionally, encrypting localStorage with a key that only can be obtained from the Origin with a secret (HTTP-only) cookie, is something we should explore.

…but nothing prevents an XSS script to just make another request to the IDP and get another set of tokens, so even if we don't use localStorage, XSS still can do whatever.

RubenVerborgh commented 5 years ago

why don't we just store the sensitive data directly in web worker?

Because that data is not persisted, so you would have to log in again every time.

However, with http-only cookies the stored keys don't get exposed to them and can't be edited by them.

Yes, but we want the client to make privileged requests to other servers. We don't want to go through the server every time.

The http-only cookies can be sent to one domain only. That's why we have hard time using them to authenticate in a distributed system, is that right?

Yes.

Would the following conversation between client, identity provider and data server be feasible to solve the issue?

Yes, but loads of roundtrips, which is what we want to avoid. But also, with XSS, anyone can make those requests.

mrkvon commented 5 years ago

But also, with XSS, anyone can make those requests.

I see. With XSS we have a problem, whether we use centralized or distributed system. It's not a problem to be solved by this library.

So it comes down to:

  1. Can we be as safe with a Solid App as with a Common Centralized App?
  2. If the XSS happens, how bad it gets? (Judged by point 1.)

I'm looking forward to seeing where this goes.

SolarBilling commented 5 years ago

Additionally, encrypting localStorage with a key that only can be obtained from the Origin with a secret (HTTP-only) cookie, is something we should explore.

Yes! I suggest that there is at least an option for all the user's data to be encrypted at rest, using a key shared by everyone who is authorized to access that data. So, for example if I want to share some data with a group "friends" then that data is encrypted with the "friends" key and the "friends" key is encrypted with the public keys of each of the members of that group. The encrypted keys can either be stored with the data or sent to each member when they are added to the "friends" group. There are a couple of possible ways to handle removing a person from the list of people authorized to access a resource:

  1. re-encrypt the data with a different key and only encrypt that key with the public keys of members who still belong to the group. or
  2. continue to check that each person belongs to the list of authorized users, before granting them access to the data - so this encryption is in addition to the existing security, rather than replacing it.

If all of the encryption and decryption is performed in the client, then the server never needs to have access to the unencrypted data.

WebID already has some support for public keys so that's a start...

kidehen commented 5 years ago

But so are cookies. And so is WebID-TLS (browser certificates).

Please explain how this extends to WebID-TLS and WebID-TLS+Delegation protocols. Note, I am referring to a world in which WebACLs protect resources and the following are loosely-coupled:

  1. Identity -- WebID
  2. Identification -- WebID-Profile Document
  3. Authentication -- WebID-OIDC, WebID-TLS, WebID-TLS+Delegation operate here
  4. Authorization -- WebACLs operates here
kidehen commented 5 years ago

@dmitrizagidulin @RubenVerborgh ,

Any comment regarding the question I posed?

We do need to keep matter clear regarding WebID-OIDC and other protocols such as WebID-TLS and WebID-TLS+Delegation which do not use Local Storage in the Browser to store credentials.

Keychain for macOS and the Keystore provided by Windows provide safe and secure storage for credentials associated with PKI, that has always been the case.

One can also use secure PEM and PKCS#12 Files to store credentials.

RubenVerborgh commented 5 years ago

Not from my side; I’m in agreement with you.

kidehen commented 5 years ago

@RubenVerborgh ,

Okay we are clear on that then :)

@dmitrizagidulin ,

You made the claim about WebID-TLS, so over to you regarding clarification.

dmitrizagidulin commented 5 years ago

@kidehen My point was to remind that no authentication method, including WebID-TLS, is immune if the user runs a compromised or malicious app (because the app can just make authenticated requests and do whatever it wants with the user's data).

kidehen commented 5 years ago

@dmitrizagidulin,

You are making a generic point about vulnerability that's universal right now.

My concern with your earlier comment.

My reading of that comment was that it appeared to be that you were speaking about a specific vulnerability that arises for Single Page Applications (SPAs) that handle authentication via WebID-OIDC (which depends on Local Browser Storage re public and private credentials). That specific vulnerability doesn't apply to either WebID-TLS or WebID-TLS+Delegation due to the fact that neither depends on Local Browser Storage for handling both credentials (public or private).

I don't want WebID-OIDC and WebID-TLS and WebID-TLS+Delegation conflated. Solid offers developers options which is a major benefit to be exploited, IMHO.

cblakeley commented 5 years ago

Though WebID-TLS doesn't use localStorage and uses credentials held in a presumably more secure keychain/keystore, isn't it still vulnerable to attack by session hijacking? If the creation of a WebID session results in an authentication cookie, couldn't a malicious script still gain access to this cookie from cookie storage? Pass the Cookie session hijacking points out that "this technique bypasses most multi-factor authentication protocols. The reason for this is that the final authentication token that the attacker steals is issued after all factors have been validated." - so the security of the protocol used to establish the session is immaterial.

If the WebID-TLS session used an httpOnly cookie, I gather session hijacking is much less of a threat - From OWASP: HttpOnly: "the majority of XSS attacks target theft of session cookies. A server could help mitigate this issue by setting the HttpOnly flag on a cookie it creates".

RubenVerborgh commented 5 years ago

The cookie mechanism is a performance optimization that, IMHO, needs to go.