Mixed content happens when some resource on a page is loaded via HTTP, while the site itself uses HTTPS. It’s a problem because that means there are files requested on an unencrypted channel, which breaks the consistency guarantees of HTTPS.
And also the browser shows your site as insecure, which is usually what prompts people to start doing something about it:
If your site is https://example.com, then an image tag like this:
<img src="http://other.com"/> makes the content to be mixed.
If you only use
https:// URLs, there is no mixed content.
CSP (Content Security Policy) provides two ways to handle this scenario. Either instruct the browser to block the unencrypted content, or auto-upgrade them.
Let’s see what is the default behavior, and how each CSP setting works!
The browser default
The browser makes a distinction between active and passive content. Active is something that runs, like a
while passive is something that is only shown, for example, an
Browsers, by default, block active mixed content but allow passive ones. While a sophisticated attacker can deceive even with a suitable image, modifying scripts can wreak havoc to a page without much effort.
But any kind of mixed content is reported by marking the site not secure.
One exception is
localhost, where all mixed content is allowed. Keep that in mind when testing locally.
With this policy directive, the passive mixed contents will be blocked too:
This is propagated inside IFrames too, so this header prevents the mixed content warning altogether, but at the expense of breaking the site if there are unencrypted contents.
If you want to upgrade all http resources to https ones, specify this header:
In practice, it rewrites mixed content such as an
<img src="http://...> to
This takes care of rewriting resource paths, but will leave references like an
Of course, you need to make sure all assets are accessible on the same URL with https.
Detect mixed content
Taking advantage of the reporting feature of CSP, you can also detect mixed content on your site. This works by forbidding unencrypted connections, but only report the violations instead of blocking them. When the users crawl the content, you’ll have a report of all the mixed content problems.
The only issue is that
block-all-mixed-content does not work with a report-only directive. So you’ll need to whitelist
https and not http. Use a header similar to this one:
Content-Security-Policy-Report-Only: default-src https:; report-uri /endpoint
Combine upgrade and report
You can also combine the last two approaches to provide better user experience while also getting the list of mixed content.
The following policy reports the mixed content, while also upgrades to https:
Content-Security-Policy: upgrade-insecure-requests; default-src https: Content-Security-Policy-Report-Only: default-src https:; report-uri /endpoint
This provides an immediate fix for mixed content, while also gives you the ability to fix the root cause.
CSP and IFrames
CSP is effective inside IFrames too. If your site blocks all mixed content, IFrames are no longer able to load resources
from http. But it also promotes the
upgrade-insecure-requests too, automatically rewriting all insecure URLs.
For a scenario when the IFrame itself comes with a header that blocks mixed content, the auto-upgrade from the page takes precedence. In effect, resources will be loaded over https instead of being blocked.
Where to report?
Scott Helme’s Report URI is an excellent service for aggregating the reports for CSP. It takes a few minutes to set up, then you don’t need to provide any infrastructure yourself.
Using an external service also helps to avoid DDoS-ing yourself. These reports can be numerous, and all your users will send them. Sending them to your server directly could easily overwhelm it.
Mixed content indicates a problem on your site, and you should fix the root cause as soon as possible. A stopgap solution is to set up a CSP that auto-upgrades all requests and reports them.
This way, you can fix all problems eventually, all while providing a secure browsing for your users.