How to Auto-Upgrade to HTTPS (aka Avoid Mixed Content)

DZone 's Guide to

How to Auto-Upgrade to HTTPS (aka Avoid Mixed Content)

Full site HTTPS migration can be hard. Consider using the Content-Security-Policy header to make it a little easier on yourself.

· Web Dev Zone ·
Free Resource

Migrating to a full HTTPS site is hard. Using “Content-Security-Policy: upgrade-insecure-requests” can reduce the “mixed-content” errors for embedded objects. Finally, use Strict-Transport-Security header to secure the domain its sub-domains.

HTTPS Migration – The Challenge

In the recent past, there has been a big push to move websites to HTTPS. Google has been dangling the carrot of a better ranking by making HTTPS as a ranking factor.

However, the biggest issue is timing the migration. If the primary site moves to HTTPS and the embedded objects do not, then the browser will block the resources. It is better to move the embedded objects over to a secure site and update the source code than to change the reference from HTTP to HTTPS.

Yet, source code change is a long drawn and difficult process. In such a scenario, Content-Security-Policy will be your friend.

Content-Security-Policy (CSP)

As per W3C, CSP is:

A mechanism by which web developers can control the resources which a particular page can fetch or execute, as well as a number of security-relevant policy decisions.

One of the directives is the upgrade-insecure-requests. When this directive is used as a header or an HTML meta-tag, the browser auto-upgrades requests to HTTP.

As per documents, 2 kinds of links are upgraded:

  • Passive mixed content
    • Embedded links: These are the references to images, stylesheets, and JavaScripts.
    • Navigational links: These are the links placed in the tags.
  • Active mixed content
    • These are the AJAX calls/XHR requests.

However, not all requests are upgraded. We learned this the hard way during a migration.

Gotcha# 1: Browser Support

First off, not all browsers support CSP. As per caniuse.com, Firefox, Chrome, and Opera are the browsers that support this directive. IE, Edge, and Safari currently do not support it.


Gotcha# 2: Exceptions

Although the W3C document mentions that navigational links are upgraded to HTTPS, both Chrome and Firefox have different interpretations.

Here’s what Mozilla says about navigation links:

  • Links on the same domain are upgraded.
  • 3rd party links are not upgraded.

Chrome, on the other hand, says this:

  • Note that having http:// in the href attribute of anchor tags (

So Chrome will not upgrade links to HTTPS.

Gotcha# 3: Third Parties

Third party content is not upgraded. Since browsers don’t know if those domains support HTTPS, they don’t upgrade. In the current versions, such content is silently blocked. You can find this blocked content by opening the developer tools in Firefox/Chrome and navigating to the console window. It would look like this example:


What’s Next?

By using the CSP header, most of the embedded object errors can be removed. CSP supports reporting as well. By enabling this, you as the content publisher can get the set of URLs being blocked/warned by browsers and fix it in the source code.

A subsequent change would be to use the Strict-Transport-Security header. This header should be enabled after the migration is complete and baked in. When this is used, the browser ensures that all requests to the domain (and subdomains) are made over HTTPS. This will eliminate the shortcomings of the plan upgrade header.

How/Where to Implement These Changes?

As the upgrade directive and STS can be implemented with HTTP headers, you can introduce it at your web server/proxy level or with your CDN. For more details on how CDN can help in such a setup, refer to my blog on “How can CDN help in SEO efforts?

https, security, upgrade, web development

Published at DZone with permission of Akshay Rangnekar , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}