How to deal with mixed content on a website

Securing your site with HTTPS is a must. As of now in 2018, Google Chrome has started labeling unencrypted websites as “unsecure” – with a large red, almost error looking icon near the address bar. All major browsers are pushing towards pointing out HTTP-only sites like this, so setting up SSL for your website isn’t just a good idea at this point – it’s a necessity.

So, you set up your site with HTTPS and reload the page, expecting the green lock (or some variation of a “high-five” from your browser). But the green lock doesn’t show. Neither does the big red “unsecure” notice. Depending on your browser, you see some sort of message (sometimes in the browser console) regarding mixed content.

Why is your browser showing these as issues?

Why is mixed content an issue?

The reason mixed-content is an issue with HTTPS-enabled sites is that it negates putting HTTPS on your site if not taken care of. HTTPS secures a channel for your site to make HTTP requests for resources your site needs. HTTP-only connections are not encrypted – even with HTTPS enabled for your site. Those non-encrypted requests are a vulnerability for your site all over again.

There are two different types of mixed-content that exist on your site: mixed passive content, and mixed active content.

Mixed passive/display content

Mixed passive content refers to content served over insecure HTTP connections, where the content in question DOES NOT have the ability to affect other parts of the site. This refers to elements like <img>, <audio>, <video>, and <object>. The threat level is lower than mixed active content, but it still is a security concern. Site attackers could still do quite a bit with your site, such as switch an image out with another inappropriate image or message, or gather information about another user’s activities based on the content that was loaded.

Mixed active content

Mixed active content refers to content served over insecure HTTP connections where the content in question DOES have the ability to affect other parts of the site (the DOM). Elements affected by this can be: <script> src attribute, <link> href attribute, <iframe> (src attribute), XMLHttpRequest requests, fetch() requests, all cases in CSS where a <url> value is used (@font-face, cursor, background-image, and so forth), <object> (data attribute), and others.

Malicious users to your site have quite a bit more to work with in regards to wreaking havoc, such as:

  • Rewrite HTTP responses to include malicious JS code
  • Steal user login credentials
  • Steal sensitive user data (credit card numbers, social security numbers, whatever might be included on the site directly or with user input)
  • Install malware directly on a user’s computer system
  • Redirect to other HTTP sites and steal HTTP cookies (which can hold important user info)

How do you fix it?

If you happen to be creating your site on WordPress, there are plugins that directly help with mixed-content resource issues. SSL Insecure Content Fixer is a plugin currently being maintained fairly often. As always, make sure any plugins you are putting on your site are needed and are still being actively worked on to keep up with WordPress updates.

CDNs (Content Delivery Networks) not only allow for securing site resources, like your image or style assets, but they also give the benefit of loading your content closer to your user and therefore loading those resources more quickly. There are a number of CDNs out there that have benefits even beyond these. At Standard Beagle, our favorite is Cloudflare.

Sometimes, WordPress has given problems with using HTTP vs HTTPS srcset images chosen from the media gallery. For example, the src attribute for the image might be using HTTPS but for some reason the srcset attribute is pulling down regular HTTP requested files. To resolve this issue (if WordPress hasn’t addressed it by the time you read this), I would highly suggest taking a look at an article on WP Tavern that refers to WordPress functions you can use to wrangle your assets into using the current HTTP protocol your site uses (which hopefully is by now HTTPS).