sandstorm-io / sandstorm

Sandstorm is a self-hostable web productivity suite. It's implemented as a security-hardened web app package manager.
https://sandstorm.io
Other
6.7k stars 704 forks source link

Allow apps to opt-in to more restrictive CSP #3410

Open zenhack opened 4 years ago

zenhack commented 4 years ago

3409 adds a content-security-policy for grains running in a ui session, which (except for some holes that we'll plug in the future) prevents grains from leaking info to the outside world from the client via any mechanism csp can control.

However, the policy does allow some things that csp can block, and that might be useful to block as an app-bug mitigation measure: things like inline scripts and use of eval().

We can't just hard-block these unconditionally, because many apps actually use them, but it would be nice if apps that don't could opt in to the extra protection offered by a CSP that blocks these things.

My notion of what this would look like is that we'd add some fields to the package definition indicating whether to enable these extra protections. The default in the schema file would be off, so that it doesn't change the behavior for existing apps, but spk init should generate package definitions that explicitly turn these on, so they're the default for "new" apps, unless the packager opts out of them.

mnutt commented 4 years ago

If there was an easy way to just diff the CSP headers an app sends and apply whichever is more restrictive that'd probably be the easiest to explain to developers and the most flexible. I also have a few routes I want to be more restrictive than others (serving untrusted content and setting sandbox attributes) and it would be nice to differentiate. But I could get by with an app-wide package definition.

zenhack commented 4 years ago

I guess we could add the information to the response types in web-session.capnp, and then have the bridge handle it.

ocdtrekkie commented 4 years ago

Isn't the bridge inside the app though? Couldn't one then implement a bridge with a less restrictive CSP?

zenhack commented 4 years ago

Maybe I wasn't super clear. The idea would be, we'd first add fields to the Response struct:

https://github.com/sandstorm-io/sandstorm/blob/93d80ac4bf2ca721f239fb58395a32970f92e953/src/sandstorm/web-session.capnp#L229

...for each of the csp sources we want apps to be able to use. So we might do something like:

enum CspSrc {
  self @0;
  dataUrl @2;
  blobUrl @3;
  eval @4;
  # ...
}

struct Response {
  # ...
  defaultSrc :CspSrc;
  scriptSrc :CpsSrc;
  # ...
}

Importantly, this type would not include variants for anything that we don't want apps to be able to allow. This is the same thing we do with everything else in the HTTP protocol; you'll note many statuses, headers & such do not have representations in web-session, which means that the grain does not even have a way of telling sandstorm it would like to set them, since the web-session protocol can't even represent them.

The bridge would only be responsible for translating between raw http (spoken by the app), and the web-session protocol, per usual. If the app sets script-src: https://evilcorp.example.com, the bridge has no way of honoring this, since there's no CspSrc value that maps to an https: directive.

ocdtrekkie commented 4 years ago

Ah, okay. Thanks for explaining.

timmc commented 2 years ago

Apparently you can set multiple CSP headers, and the browser will do the work of figuring out the intersection: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#multiple_content_security_policies