Search code examples
iframehrefmailtocontent-security-policy

mailto href inside frame not working when Content Security Policy


Summary:

Site at https://localhost:3000 , with Content-Security-Policy value of default-src 'self' 'unsafe-inline' https://localhost:3001/https_index.html contains iframe pointing at https://localhost:3001/index.html. The contents of :3001/index.html contain an <a href="mailto..."></a>. Clicking that link fails: Refused to frame '' because it violates the following Content Security Policy directive.... How can I change my CSP value to prevent this error; to open an new email in user's preferred email client (normal behavior of mailto)? I am using Chrome1

Detail:

Similar but different than this question "mailto link not working within a frame chrome (over https) "

I think mine is not a duplicate because:

  1. I cannot reproduce that bug, I see a console warning about mixed-content when I try to reproduce their steps:

    Mixed Content: The page at 'https://localhost:3001/https_index.html' was loaded over HTTPS, but requested an insecure resource 'mailto:...'. This content should also be served over HTTPS.

  2. My steps are specific; both my page & its iframe src are https, but the page itself is served with a specific and restrictive Content-Security-Policy (CSP):

    app.use(csp({ directives: { defaultSrc: ["'self' 'unsafe-inline' https://localhost:3001/https_index.html"] } }));

  3. Also the resulting error I can reproduce is different:

    Refused to frame '' because it violates the following Content Security Policy directive: "default-src 'self' https://localhost:3001/https_index.html". Note that 'frame-src' was not explicitly set, so 'default-src' is used as a fallback.

With an image like: showing Google Chrome sad-face icon suggesting error; the message says 'Requests to the server have been blocked by an extension'

  1. The accepted answers for the original questions will help me work around my CSP-specific issue, that is, if I add a target="_top" to the link, the email client opens without error: <a target="_top" href="mailto:...">email</a> A similar fix works for another similar but different issue. However, this may1 sometimes open a new tab

So my question is specifically about the Content-Security-Policy error (see above):

...Refused to frame '' because it violates the following Content Security Policy directive: ...

Notice it says frame ''. The frame is identified as an empty string!

Normally if some resource violates CSP, the URL of the resource is identified; i.e.

Refused to laod the script 'http://evil.com/evil.js'...

And if the CSP-violating URL is identified + provided I can use it; add it to my CSP value for default-src:

`app.use(csp({
  directives: {
    defaultSrc: ["http://evil.com/evil.js 'self' 'unsafe-inline' https://localhost:3001/https_index.html"]
    }
  }));`

But can I allow an exception for an href value? Specifically for mailto? I tried wildcards like mailto*, but:

The source list for Content Security Policy directive 'default-src' contains an invalid source: 'mailto*'.

And I wonder if any wildcard would work anyway; does Chrome really consider the href="mailto..." frame as an empty string? I suppose so, since it's not a URL per se; Chrome "wants" to launch an external application (i.e. Outlook) in the context of the iframe; who is bound to the CSP rules of its parent page...

Footnotes:

  1. Chrome displays the above errors in CSP or sandbox cases. Internet Explorer doesn't complain about an iframes href, despite the value of CSP. Internet Explorer also doesn't have the "new tab" problem, despite the value of sandbox. IE 11.1914 will just give message:

Internet Explorer dialog asking user to confirm they want to allow this page to open Outlook to a source of href, and choose to ignore this message in future

  1. The fix of using target="_top" may open a new tab , if you've sandboxed your iframe! (sandbox is different than CSP). I don't like the new tab. Chrome gave me this error...

    Unsafe JavaScript attempt to initiate navigation for frame with URL 'http://localhost:3000/' from frame with URL 'https://localhost:3001/index.html'. The frame attempting navigation of the top-level window is sandboxed, but the flag of 'allow-top-navigation' or 'allow-top-navigation-by-user-activation' is not set.

... but opened a new tab, as well as the Outlook email client...

showing a new tab opened in Chrome browser, whose URL is set to the "mailto:" value from within the iframe

I did what the error suggested; modifying the value of the iframe sandbox attribute: sandbox="allow-top-navigation allow-same-origin ...", and the mailto link worked (as before), but did not open an excessive new tab. Great!


Solution

  • Stumbled upon this question after encountering the same issue. There is surprisingly little documentation about this after hours of searching.

    My first instinct was to do something like you were doing, mailto* or mailto:*.

    What finally ended up working was omitting the wildcards, and altering the frame-src directive as such:

    frame-src 'self' mailto: tel: *.mydomain.com

    tel: links were also were broken in iframes.