16
votes

I am looking for an approach to allow only whitelisted scripts to run within a sandboxed iframe. I was thinking of an iframe-sandbox directive that allows only whitelisted scripts to run within an iframe. The analogy is the script-src directive in the Content Security Policy.

The problem:

<iframe sandbox="allow-same-origin allow-scripts" src="https://app.thirdparty.com" width="100%" height="800" frameBorder="0"></iframe>

The app in the iframe provides valuable functionality for my website. However, it pulls in external resources that I would like to control (i.e., block), e.g., AnalyticsJavaScript.com and TrackingPixel.com. I would like to allow scripts from app.thirdparty.com but block AnalyticsJavaScript.com and TrackingPixel.com.

Any help appreciated.

2
The W3C webappsec group is working on the Editor's draft Content Security Policy: Embedded Enforcement (w3c.github.io/webappsec-csp/embedded/#allow-csp-from-header). Not a REC yet.rvaneijk
CSP:EE is a feature that has shipped in Chrome 61, and Opera 48.! However the feature is still in Editor's Draft in terms of the W3C Spec, and there are no public signals from other browsers to implement the feature.Austen Holland

2 Answers

6
votes

The answer to this is unfortunately complicated. With the advent of iframe sandboxing the question seems simple enough, but the spec that you're looking for is very much a work in progress. Thus, if you want decent browser support, the issue devolves into how to modify an iframe's content, which usually involves some sort of proxy.

Content Security Policy

The spec you really need is the CSP. At its simplest, you would allow specific scripts with the iframe atribute csp="...".

<iframe ...
        src=""
        csp="script-src https://app.thirdparty.com/"
        ...></iframe>

Any scripts from domains not specified (i.e. tracking scripts as in the question) would not be allowed in the response. Note that limiting scripts to those from a specified source does rely on cooperation with the third party app's server. If the server does not inform the user agent that it will adhere to the CSP restrictions then the response will be blocked.

The CSP is still a working draft and may change in the future. As stated in the comments, Chrome 61 and Opera 48 have implemented the CSP spec, but at this stage there is no sign from Firefox, Edge or Safari that they will also implement it. Unless you can guarantee that your users will only be using a browser that supports the spec, the tracking scripts will still be present for a very large percentage of users.

The remaining suggestions all involve modifying the iframe's content to remove the offending scripts.

Reverse proxy

Creating a reverse proxy to block a couple of tracking scripts in an iframe is probably equivalent to using a nuclear warhead to light a camp fire as far as overkill goes. But, if you are able to configure your server to this extent, it is the most reliable and seamless method for iframe content injection/modification/blocking that I've found.

The Wikipedia page states:

A reverse proxy is a type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client, appearing as if they originated from the proxy server itself.

Because the reverse proxy is an intermediary between the third party app and your site, it can transparently modify the responses to remove the undesired scripts. I'll use Apache in this example, but your implementation really depends on what server you're already using.

You need a subdomain for the proxy that points to your server IP, e.g. proxywebapp.yourdomain.com. On your server you would then create a virtual host in httpd.conf that uses the Apache mod_proxy module. Within your virtual host configuration you would then substitute the script calls to AnalyticsJavaScript.com and TrackingPixel.com with blanks. If the third party app must use HTTPS then reverse proxying gets trickier as you need an SSL virtual host and a SSL certificate for the proxy's FQDN.

<VirtualHost *:*>
    ServerName        proxywebapp.yourdomain.com
    ProxyPreserveHost On
    ProxyPass         "/" "http://app.thirdparty.com/"
    ProxyPassReverse  "/" "http://app.thirdparty.com"

    # in case any URLs have the original domain hard coded
    Substitute        "s|app.thirdparty.com/|proxywebapp.yourdomain.com/|i"
    # replace the undesired scripts with blanks
    Substitute        "s|AnalyticsJavaScript/| /|i"
    Substitute        "s|TrackingPixel/| /|i"
</VirtualHost>

Your iframe would then point to proxywebapp.yourdomain.com.

<iframe ... src="proxywebapp.yourdomain.com" ...></iframe>

Again: total overkill but should work transparently.

Proxy scripts

A third option to consider is implementing a proxy script on your server between the iframe and third party app. You would add functionality into the proxy script that searches for and removes the undesired scripts before they reach the iframe. Additionally the proxy means the iframe's content will validate the same-origin policy, thus you could instead remove the undesired content with JavaScript in the frontend, although this may not guarantee that the scripts won't run before they are removed. There are many proxy scripts available online for all manner of backends (PHP, Node.js etc. ad nauseum). You would likely install the script and add it as the iframe's src, something like <iframe ... src="proxy.php?https://app.thirdparty.com/" ...>.

Unless properly configured for all cases, the proxy may not correctly transfer data between the third party app and its parent server. Testing will be required.

Writing your own server side proxy to remove a couple of scripts from an iframe is probably a bit excessive.

If you can't access the backend, it is possible to scrape the web app's content using JavaScript and a CORS or JSONP web app, and modify it to remove the scripts. Essentially making your own proxy in JavaScript. Such web apps (Any Origin, All Origins, etc) allow you to bypass cross-domain policy restrictions, but because they are third party you can no longer assume any of the web app's data is private. The issue with correctly communicating any data transfer between the app and its parent server will still be present.

Summary

A widely supported pure frontend solution is not feasible at the moment. But there are many ways to skin a cat and perhaps even more ways to modify an iframe's content, regardless of cross-domain restrictions.

Content Security Policy does look promising and is exactly what you're asking for, but currently its lack of widespread support means it can only be used in very niche situations. A reverse proxy that modifies content may take a lot of configuring and in this situation is like driving a full size semi-trailer over a Hot Wheels track, but will likely operate seamlessly. Content modification from a forward proxy is somewhat simpler to implement, but may break communications with the third party app's parent server.

0
votes

You can't do this the way you want (for now). As mentioned in comments CSP:EE is a thing yet to come.

However you can try proxying the request and removing the unnecessary scripts from the body on the server side or on the client side, e.g.:

1) Get the needed page via XMLHTTPRequest

2) Remove unwanted

3) Inject into iframe on the page

"Workability" of this method depends purely on external app functionality. I.e. it will not work if the aforementioned app needs registration/authorisation of the end user to work, however this can still be suitable for some simple cases.

P.S.: you can implement a workaround to make such thing work via browser extension, however I'm sure this is not what you want.