Search code examples
javascriptgoogle-chromehttphttpschromium

does mixed content error mentioning script mean that the problem comes from an HTML <script> tag?


In Google Chrome on Windows, I am seeing a mixed content error it readings something like this:

Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure script 'http://...'. This request has been blocked; the content must be served over HTTPS.

Does the word script in this message imply that what is happening is that either in the initial HMTL payload or sometime later in the DOM via JS a <script> tag is being created that points to an http:// prefixed src? Can I be sure that this error is not being generated by a different type of request such as a fetch() or other XHR/AJAX?

Do I understand this correctly?

I was looking into the Chromium source code and it seems like the presense of the script word in the error message means that the "Request Context Type" is SCRIPT, but does that mean an HTML script tag with a src attribute?


Solution

  • TL;DR

    The word "script" in the message means that the specific non-https resource that was blocked from loading in this case was of type "script". Why exactly that non-https resource request was generated in the first place is not covered in the error message...

    Most browsers will block http resources from loading on https sites now. Best practice is https for everything (main site and all things loaded by that site).

    To track down where that http call is coming from...

    • open your browser dev tools
    • clear cookies
    • go to "network" tab and disable cache
    • refresh page and look for the blocked request
    • the network panel will usually show an "initiator" column that tells you which script/file initiated the call. Might be index.html, might be some other script. If you don't see the column it might be hidden and right clicking on the column headings area may allow you to choose which columns are shown.

    More details

    Mixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure_____ 'http://...'. This request has been blocked; the content must be served over HTTPS.

    Browsers (not just chrome) have been doing this for a while as a security feature.

    Imagine that your eCommerce website https://www.example.com is served securely. However you load a javascript file from http://www.example.com/site.js insecurely. Because that site.js was served insecurely, it could easily be modified by a Man in the Middle (MITM) to do things like steal credit card numbers from the customers of your shop during checkout.

    Even passive ("display") content like images has issues when serving insecurely. As an example...A man-in-the-middle could rewrite the image response to redirect to another URL on another domain that enables them to set cookies on your users in order to later serve your customers ads for your competitor. Or just changing the images on your site to display something else.

    In general the web has moved to https only for all sites. The availability of free, auto-renewing, domain-validation certificates from LetsEncrypt has made this relatively trouble-free.

    Server Name Indication (SNI) TLS extension support (all major OSes after Windows XP) also means that https works properly even when different domains are served from the same IP address (cheap/budget shared hosting). So really no excuses not to do https by default.

    Current best practices (just the basics...lot more you can do):

    • redirect all http to https for your domain(s)
    • utilize certbot to automate receiving domain-validated certs for your domain from LetsEncrypt. All modern web-hosting companies should be handling this automatically for you. If you run/manage your own server then you need to setup certbot yourself.
    • all resources (stylesheets, scripts, images, fonts) loaded by your site should be https. If you use a CDN on a different subdomain, that should also be secured.
    • use http-only, secure cookies.
    • use content security policy to lock down which domains/resources are allowed on your site (prevent hacked third-party resources from easily exfiltrating your users' data via calls to unauthorized domains).
    • lots more you can do if you are handling sensitive data...

    Some example scenarios...

    • initiator: index.html - the reference to that script is in the actual html file.
    • initiator: site.js - the initiator is in one of your site's javascript files or the configuration for a react/vue/angular/etc javascript app
    • initiator: gtm.js - the initiator is inside google tag manager. check your pixels in the google tag manager interface...most likely will be a custom html pixel needs to be updated from http to https.
    • initiator: site.css - might be you have a font or image url in your css file that needs to be updated from http to https.
    • initiator: some-plugin.js - some wordpress plugin or other javascript-based widget you have added to your site is generating an insecure request.

    References