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

Per-type enforcement #66

Closed
koto opened this issue Jun 22, 2018 · 10 comments
Closed

Per-type enforcement #66

koto opened this issue Jun 22, 2018 · 10 comments
Assignees
Labels
Milestone

Comments

@koto
Copy link
Member

koto commented Jun 22, 2018

Right now all the types can be enforced as a group. This happens for good reasons:

  • comprehensive DOM XSS containment requires guarding all relevant sinks (but see Consider dropping TrustedURL #65, as containment does not always require having configurable policies)
  • it's simple for authors. You enforce policies to stop DOM XSS (via trusted-types CSP directive), or not.

However, it has one downside: the type list needs to be complete from the get go, as adding new types would break existing TT sites. We can already see interesting candidates for next batch of types - TrustedTemplate, or TrustedStylesheet, TrustedStylesheetURL, and if our approach turns out successful, I'm sure there will be more.

This issue is to explore how we can change the enforcement declarative syntax to accomodate for potential new types.

Option 1: Enforce each type separately via keywords

trusted-types 'enforce-html' 'enforce-url' 'enforce-script-url

Adding new types becomes then just adding new policy create* functions and a new keyword. The downside is, the secure setting requires you to know about all possible types, although we can simplyfy this, and just assume that existing DOM-XSS related types are enabled by default if trusted-types directive is present, and leave the enforce-* keywords for new, optional types. (e.g. TrustedURL might be optional - see #65).

Option 2: Tie type enforcement into existing CSP directives

script-src 'require-trusted' <other scripty restrictions>; 
navigation-to 'require-trusted' <additional limits>; 
trusted-types my-policy dompurify-policy

Under this definition, scripts sinks would have to be typed, on top of their existing restrictions. Stylesheets, when introduced, would just add style-src 'require-trusted'. It's a bit clunky, as there's no 1:1 mapping between directives and types (e.g. there's no setting for TrustedHTML, both TrustedScript and TrustedScriptURL are under script-src), and it ties the whole TT quite deeply into existing CSP syntax with all its problems.

Application could live on the edge by specifying default-src: 'require-trusted' to be opted into all possible types.

@koto koto added the spec label Jan 17, 2019
@koto
Copy link
Member Author

koto commented Mar 11, 2019

To update: we'll need per-type enforcement, given that the new types are likely to appear, and e.g. some authors may wish to control TrustedURLs via existing CSP mechanisms. See also mozilla/standards-positions#20.

@mikesamuel
Copy link
Collaborator

Semantically, can't this be done via a default policy that has the identity function for conversions that the application wants to opt out of?

Is that not practical?

@koto
Copy link
Member Author

koto commented Mar 27, 2019

That would still break applications if new types are being added.

@mikesamuel
Copy link
Collaborator

So the tradeoff then is CSP policy complexity vs flexibility in adding new types?

One way to avoid that tradeoff is with a catchall: createTrustedDefault.

@koto
Copy link
Member Author

koto commented Mar 27, 2019

So the tradeoff then is CSP policy complexity vs flexibility in adding new types?

Correct.

@mikesamuel
Copy link
Collaborator

I'm against specifying more than the bare minimum in header content.

We ought prefer moving the complex portion of a policy in a general purpose programming language, not an ad-hoc language in a header. It seems that a catchall like policy.createTrustedDefault(x, type) would achieve that.

Lengthy policies should be shipped in cacheable body content, not header content. If most CSP policies are written in <meta> tags, then that's fine, but IIUC that's not the case.

As argued in #139 (comment) I think we should bias against adding new trusted types, but acknowledge that some will probably be necessary.

@koto
Copy link
Member Author

koto commented Apr 8, 2019

Ack, those are valid points, though I think we can generalize the issue at hand to declarative vs programmatic configuration. (e.g. the fact that the header is not cacheable is a separate issue we could fix by e.g. putting the configuration in an Origin Policy or a well-known file).

Parts of TT are already programmatic (e.g. createPolicy, default policy), with some declarative parts (the limit on policy names, the report-only-mode). I think we should have a balance here, and can't go fully programmatic. For example:

  • we might end up needing inheritance rules for local schemes documents, like CSP to avoid bypasses, even accidental ones. It feels more natural for that to be controlled by a header, than by JS.
  • for some deployments it's easy to control response headers in a deployment, but it's not easy to ship JS code (especially code that needs to run early and once only). For example, that can be provided trivially by a lot of middleware solutions, and makes Report-Only deployment at Google possible.

We can't go fully declarative either, as we'll quickly end up with a complex DSL - CSP demonstrates what happens then.

For now the line is drawn that only the allowed policy names, reporting URL and the enforce/report/ignore behavior are configured declaratively. I want to explore whether it makes sense to have per-type enforcement be declarative as well. This changes the syntax of the configuration a bit, but maybe not so much (especially with option 2). That's for practical reasons: I end up almost always writing a default policy that is an equivalent of no unsafe-inline for TrustedURLs. This feels redundant.

cc @mikewest @otherdaniel - is there a canonical bug for the 'csp as a compilation target' idea?

@mikewest
Copy link
Member

mikewest commented Apr 8, 2019

FWIW: I would very much like origin policy to be the solution here when it exists. I would love for us collectively to stop abusing response headers as policy configuration mechanisms.

is there a canonical bug for the 'csp as a compilation target' idea?

Just the only-kidding-but-no-really-we-should-do-this "spec" at https://mikewest.github.io/artur-yes/.

@koto koto self-assigned this May 4, 2019
@koto koto added this to the v1 milestone Jun 24, 2019
@craigfrancis
Copy link

@mikewest, while I'm looking forward to the origin-policy existing, it will apply site-wide, so I only see it as being a baseline (or set of fallbacks) for the whole site.

Whereas individual response headers (for each page) can be customised to lock that page down as much as possible.

Or am I missing something?

In my case, most pages do not use any trusted types (so it can use null), but some pages use ~4 trusted types (one of my websites has 14, but not all are used on a single page).

So for my origin-policy, I'd have to include the full list of 14 trusted types for the baseline (not ideal if I can't lock it down any further); or, as per your current CSP experiments, I'd prefer to provide a fallback of null when an individual response header wasn't set for that page.

@koto
Copy link
Member Author

koto commented Jul 17, 2019

The current plan is to ship 4 types that focus on DOM XSS only (TrustedURL, TrustedScriptURL, TrustedScript and TrustedHTML). TrustedURLs will only be used for navigational sinks (iframe.src, window.open and such) and moslty because this is where javascript: URLs work. - I filed #192 to track this).

There are no custom (user-defined) types planned, authors might use an approach like https://gist.github.com/koto/1d044f6029ee337beffb4487b80f8b02 to add a support for them.

If additional types will surface (e.g. something for wasm), or we'd need another breaking (i.e the API introduces new enforcements) change in the future, we can introduce it via a new CSP directive keyword. But for now it seems like per-type enforcement is not needed - the types are "stable".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants