iFrame Sandbox with Content Security Policy

2019-06-20 05:05发布

问题:

I assume that this is just a simple misunderstanding of the spec. However, I'm having an issue with including scripts in iFrames protected by sandboxing. Specifically, the code I am dealing with is below.

In top.html:

<iframe src="framed.html" sandbox="allow-scripts"></iframe>

In framed.html

...
<head>
  <meta http-equiv="Content-Security-Policy" content="script-src example.com">
  <script src="http://example.com/script.js"></script>
</head>
...

When running this file in Chrome, it gives me the error:

Refused to load the script 'http://example.com/script.js' because it violates the following Content Security Policy directive: "script-src localhost:9000".

Why is it blocking the script from loading? I know that without allow-same-origin, the iFrame gets a completely unique origin that is not equal to any other origin. Therefore, script-src 'self' wouldn't work. However, I am trying to load the script from an origin explicitly called for in the CSP. Thoughts?

Update: Created JSFiddle to showcase the issue.

回答1:

When you use a sandboxed page with a unique origin, you can't put a host without scheme in the CSP, that's why the policy is violated. Use script-src https://example.com or script-src http://example.com or even script-src https://example.com https://example.com , and the CSP will correctly be relaxed (note that the CSP is whitelist-based, by default most things are disallowed).


As the grammar from the CSP specification shows, the scheme in a CSP directive is optional:

; Schemes: "https:" / "custom-scheme:" / "another.custom-scheme:"
scheme-source = scheme-part ":"

; Hosts: "example.com" / "*.example.com" / "https://*.example.com:12/path/to/file.js"
host-source = [ scheme-part "://" ] host-part [ port-part ] [ path-part ]
scheme-part = scheme
              ; scheme is defined in section 3.1 of RFC 3986.
host-part   = "*" / [ "*." ] 1*host-char *( "." 1*host-char )
host-char   = ALPHA / DIGIT / "-"
port-part   = ":" ( 1*DIGIT / "*" )
path-part   = path-abempty
              ; path-abempty is defined in section 3.3 of RFC 3986.

But a sandboxed frame without the allow-same-origin token will have a null origin, and the URL matching algorithm does not allow scheme-less directives to match (relevant parts of the algorithm shown below):

6.6.1.6. Does url match expression in origin with redirect count? Given a URL (url), a source expression (expression), an origin (origin), and a number (redirect count), this algorithm returns "Matches" if url matches expression, and "Does Not Match" otherwise.

...

If expression matches the host-source grammar:

  1. If url’s host is null, return "Does Not Match".

    1. If url’s host is null, return "Does Not Match".
    2. If expression does not have a scheme-part, then return "Does Not Match" unless one of the following conditions is met:

      1. origin’s scheme is url’s scheme
      2. origin’s scheme is "http", and url’s scheme one of "https", "ws", or "wss".
      3. origin’s scheme is "https", and url’s scheme is "wss".

In the given example:

  • origin is null (because of the use of sandbox without allow-same-origin).
  • url is http://example.com/script.js

The null origin's scheme does not match any of the last three cases, so the host name without scheme won't match any URL, and therefore the policy is violated.