Mixed content takes place whenever initial HTML is loaded over a secure HTTPS connection while other resources (e.g. scripts, images, videos) are loaded over an unsecure HTTP connection. Due to the fact that the initial request was secure over HTTPS, and both HTTP and HTTPS need to be loaded to display the same page, this is deemed mixed content.
The Benefits to HTTPS
HTTPS is the secure version of HTTP, the protocol via which data is sent between your web browser and the website you are visiting. The ‘S’ stands for ‘Secure’, referencing the fact that all communications between your browser and website are encrypted. There are three key benefits to the HTTPS protocol: Website authentication Data integrity Secrecy
The lock icon in the browser address bar indicates that the site you are visiting has a functional SSL certificate and all resources have been loaded securely over HTTPS.
How HTTP Weakens Security
When a site has mixed content, however, the security of the whole page is weakened. HTTP requests are vulnerable to man-in-the-middle attacks in which an attacker can eavesdrop on a network connection and witness or change the communication between two parties. By the time a browser reports mixed content warnings to the user, the page’s security has likely already been compromised.
This scenario is fairly common, and while browsers do block all HTTP requests when a site is accessed via HTTPS, the on-page impacts are not always immediately visually apparent, which is why the browser delivers the mixed content warning alerting the developer to fix the errors in his/her application.
Example of a Common Mixed Content Error
There are several scenarios that can lead to mixed content errors, but the most common culprits are absolute links that point to images or files via an HTTP request (perhaps relics from an older version of the site). In this case, when the site is accessed via HTTPS, it can lead to missing images, absent styles and a lack of functionality in the dynamic content.
Web browsers will issue warnings about this kind of content in the developer console, letting the user know the page has insecure resources, such as:
Mixed Content: The page at 'https://example.com/' was loaded over HTTPS, but requested an insecure image 'http://image.com/image.jpg'. This content should also be served over HTTPS.
How to Address Mixed Content Errors
There are several options for addressing mixed content errors:
-
You can fix the URLs embedded in the content that your origin served by replacing the
http://
prefix withhttps://
on any absolute URLs. HTTP pages can reference HTTPS resources, but this doesn’t work the other way round. It’s also worth noting that while protocol-relative urls might sound like a good idea for ensuring that links use the same protocol as the page, it is always best to use HTTPS (even on HTTP pages) because the protocol-relative approach will result in browser-cache-misses when the site moves from a HTTP page to a HTTPS page. HTTPS is fast and free on Section. In addition to security, favoring the HTTPS resource will always have cache benefits in the browser and at Section. -
If you are unable to change the content served by your origin and you have a Section proxy configured that is able to insert additional response headers, you can ask web browsers to solve it themselves. If you have Varnish Cache, for example, this custom VCL can be used:
sub vcl_deliver { if (req.http.X-Forwarded-Proto == "https" && !resp.http.Content-Security-Policy) { set resp.http.Content-Security-Policy = "upgrade-insecure-requests"; } }
This works by adding a Content-Security-Policy: upgrade-insecure-requests header that all modern browsers will honor, thereby automatically translating any broken
http://
URLs on your pages tohttps://
. -
Finally, if you still have to support older browsers or devices that don’t understand the Content-Security-Policy header and you have configured the OpenResty proxy via Section, you can fix the URLs as the content passes through the Section platform with Lua script similar to this:
if ngx.header["content-type"] ~= nil and string.find(ngx.header["content-type"], "^text/html") then local chunk, eof = gz.inflate_chunk() chunk = chunk:gsub("src=\"http://", "src=\"https://") gz.deflate_chunk(chunk) end