Content Security Policy: Feature Detection

AngularJS’s latest release candidate is the first framework I’ve seen that cleanly supports a content security policy that restricts usage of eval(), new Function(), and the like. I’m thrilled to see this happening, and it’s a testament to the priority that the Angular developers place on security. CSP is quite simply one the best XSS-protection mechanisms available to developers these days in modern browsers. The more frameworks that hop on board, the faster sites can start adopting CSP, and the safer we’ll all be on the net.

All that said, the implementation isn’t as complete as it could be. Angular requires that the developer manually opt into CSP-friendly mode via the ng-csp directive. This is error-prone at best, and introduces complexity that would be better hidden away inside the framework. The Angular developers recognize this shortfall, and are explicitly requesting some sort of feature detection API that would allow frameworks to query the currently active policy to determine its boundaries, and fork their implementation accordingly.

This does seem like a great addition to the spec; I’d suggest the following implementation:

Add document.[prefix]contentSecurityPolicy as an object that exists in browsers that support CSP. This would enable trivial feature detection of CSP as a whole, which would enable frameworks to make intelligent decisions about how to proceed through the following use cases:

  1. Is a policy enabled? If not, perhaps I’d like to set one via meta injection.

    document.contentSecurityPolicy.active is a boolean property: true if a policy is set, false otherwise.

  2. Can I execute eval() or use new Function()?

    document.contentSecurityPolicy.isWhitelisted('script-src', 'unsafe-eval') returns true if unsafe-eval has been defined for the script-src directive.

  3. Can I embed a data: image or frame?

    document.contentSecurityPolicy.isWhitelisted('image-src', 'data:') and document.contentSecurityPolicy.isWhitelisted('frame-src', 'data:')

  4. Can I include Google Analytics?

    document.contentSecurityPolicy.isWhitelisted('script-src', 'https://ssl.google-analytics.com') (Note that isWhitelisted should do the hard work of dealing with wildcards. This example should return true if *.google-analytics.com is whitelisted.)

  5. Are reports being sent? If so, where are they going?

    The document.contentSecurityPolicy.reportUri property is either undefined if no report-uri directive is set, and a URI if the directive is set.

This seems like a reasonable first pass at a strawman for discussion. Thanks to Paul Irish, Eric Bidelman, and Pete LePage for walking through this with me.

What do you think?