15

Problem

I'm developing a website served using HTTP protocol. In development I use Webpack with it's webpack-dev-server, which serves the page locally on http://localhost:9090.

I was surprised to see in Firefox 58 console the following mixed content error about loading the font file. It's weird to me, cause the page is served using HTTP not HTTPS and I thought mixed content errors are limited only to HTTPS pages.

`Blocked loading mixed active content “http://localhost:9090/b1aa06d82e70bbd5a14259a94c9bbb40.ttf”

I found out that the source of the error is YouTube video embedded in an <iframe> on the page (<iframe src="https://www.youtube.com/embed/...>). As soon as I remove the YouTube embed, the error disappears from the console.

I don't understand this behavior, cause it's not nested HTTPS iframe which is making this font request, but the outer HTTP page (top-level browsing context)!

Summary

The outer page (top-level browsing context) is served using HTTP. Only it's embedded iframe is fetched using HTTPS. The HTTP request for a font file that the outer page makes (not the embedded iframe) produces mixed content error in Firefox 58 console.

Code Examples

To give a working example I created 2 pens on Plunker, which is served over HTTP and imports (the Plunker site itself, not my code) WOFF font Font Awesome over HTTP.

The example With error, which has YouTube iframe embedded over HTTPS, produces the following error in Firefox 58 console: Blocked loading mixed active content “http://plnkr.co/css/font/Font-Awesome-More.woff”.

The example Without error, which is the same code just having the iframe removed, produces no error.

Questions

  • How can you have a mixed content on a website loaded using HTTP protocol? I thought mixed content can only exist on websites loaded using HTTPS. Does requiring any resource over HTTPS (like it's done by YouTube embed) makes all the content required over HTTP mixed content?
  • How can I fix the error? I don't plan to serve website over HTTPS and I want my fonts to load properly on the production HTTP server.
Jordi Vicens
  • 696
  • 7
  • 17
Robert Kusznier
  • 6,471
  • 9
  • 50
  • 71

5 Answers5

10

It seems that Firefox caches fonts and tries to execute a request to the cached font by use of the URL the font was originally delivered from. That leads to the mixed content error.

I saw that problem with font awesome fonts when I deployed a web application to the server running HTTPS which I had developed on a local server running HTTP. When requesting the remote site Firefox reports:

Blocked loading mixed active content “http://localhost:8080/fontawesome-webfont.woff2”

That impressed me because there is no request to localhost coded in that web application.

In your example the font is loaded by

http://plnkr.co/css/apps/editor-1.6.1.css

which is url(../font/Font-Awesome-More.woff)

One of the CSS or scripts loaded by the iframe must then try to load that font again maybe using a dynamically constructed URL.

I don't know anything about the font caching strategy implemented in Firefox - maybe they identify the font by its name - but one of the solutions I found for my case is to "Forget About This Site" localhost in the history of Firefox.

A solution for your case could be to switch to HTTPS

Jordi Vicens
  • 696
  • 7
  • 17
Uwe Voigt
  • 170
  • 2
  • 10
  • Unfortunately switching to HTTPS is not possible in my case. And I don't think that's a real solution - switching to HTTPS only because you have problems with loading perfectly legal font file sounds like a big overkill. – Robert Kusznier Feb 11 '18 at 12:53
  • I'm seeing the same in Firefox 58.0.2. In my case, the offending fonts aren't even referenced on my page. My site is behind `https://`, as are all external references (including fonts). If I open the Developer Tools Webconsole, I see "mixed contents" errors for fonts loaded in an entirely unrelated tab. Once I close that tab and reload my own site, the errors go away. Go figure. Anyway, the Webconsole has all the details. If the error is not visible, check the Filters in the web console (if you're lucky, there's even a link to clear the filters). – BertD Feb 23 '18 at 21:22
  • 3
    There is something *very* wrong because I am seeing fonts from *completely unrelated* sources... – Antti Haapala -- Слава Україні Mar 21 '18 at 19:28
  • I also see fonts from seemingly unrelated sources, but definitely only when visiting pages in my history. – Lucas Apr 09 '18 at 01:32
4

I had the same issue. I resolved it by using a relative path instead of an absolute path.

Since my fonts are being called from this CSS "/styles/my.css", and my fonts were located in "/fonts/Open_Sans..."

Before (with FF errors):

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/Open_Sans/OpenSans-Light.woff2") format("woff2"),
  url("/fonts/Open_Sans/OpenSans-Light.woff") format("woff");
  font-weight: 300;
}

After (without FF errors):

@font-face {
  font-family: "Open Sans";
  src: url("../fonts/Open_Sans/OpenSans-Light.woff2") format("woff2"),
  url("../fonts/Open_Sans/OpenSans-Light.woff") format("woff");
  font-weight: 300;
}
Modular
  • 6,440
  • 2
  • 35
  • 38
0

Since you're having problems on Firefox's end, follow their given documentation, How to fix a website with blocked mixed content:

How to fix your websiteEdit

The best strategy to avoid mixed content blocking is to serve all the content as HTTPS instead of HTTP.

For your own domain, serve all content as HTTPS and fix your links. Often, the HTTPS version of the content already exists and this just requires adding an "s" to links - http:// to https://.

However, in some cases, the path may just be incorrect to the media in question. There are online as well as offline tools (depending on your operating system) such as linkchecker to help resolve this.

For other domains, use the site's HTTPS version if available. If HTTPS is not available, you can try contacting the domain and asking them if they can make the content available via HTTPS.

ReyAnthonyRenacia
  • 17,219
  • 5
  • 37
  • 56
  • 1
    I've read that article, but I wouldn't like to configure my whole site for HTTPS, just because one resource (YouTube iframe) uses HTTPS. I understand the vulnerability you create when you try to access resources by HTTP on HTTPS website, but my website is served using HTTP (so it don't make claims that it's totally secure) and the whole blocking issue seems ridiculous to me. – Robert Kusznier Nov 29 '17 at 15:32
  • 1
    Also, there is no mixed content, it is a plain HTTP site. There is no HTTPS. – Tyler Durden Jan 24 '18 at 16:14
0

I encountered this problem as a result of my live and staging servers being HTTPS, and my local/dev copy being HTTP.

I solved it by generating my CSS dynamically, and using inline data: fonts in the CSS, rather than URL references. This removes any URL information associated with a font, and so avoids any possible cross-site cache contamination.

In my case I have used PHP, but this could be changed to any server-side language.

<?php
// Declare this as a CSS file for the browser
header('Content-type: text/css');

/*
 * Respond with 304 if the content was served recently
 *
 * The logic here is:
 *
 * We get a IMS date in the request e.g. 21:00 (Then)
 * We look at the current time e.g. 21:30 (Now)
 *
 * So (Now - Then) must be < 60 * 60
 */
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
{
    $thenTime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if(time() - $thenTime < 60 * 60)
    {
        header('HTTP/1.1 304 Not Modified');
        exit;
    }
}

// Tell the client the resource was modified on the last hour
$modifiedDate = gmdate('D, d M Y H:00:00 T', time());
header('Last-Modified: ' . $modifiedDate);

?>
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300;
  src: local('Open Sans Light'),
       local('OpenSans-Light'),
       url(data:application/x-font-woff;charset=utf-8;base64,<?php echo base64font('open-sans-light.woff') ?>) format('woff');
}

@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans'),
       local('OpenSans'),
        url(data:application/x-font-woff;charset=utf-8;base64,<?php echo base64font('open-sans-normal.woff') ?>) format('woff');
}

<?php

function base64font($file)
{
    $fontFolder = realpath(__DIR__ . '/../fonts');
    $data = file_get_contents($fontFolder . '/' . $file);
    $base64 = base64_encode($data);

    return $base64;
}

I have set the 304 header to kick in if the copy already served to the browser is recent. You don't have to have this, but it will improve performance if you do. Font definitions rarely change, so you could make this delay longer on high-traffic sites.

halfer
  • 19,824
  • 17
  • 99
  • 186
0

That's because you are trying to call an http link since an https url, you just have to change them to be the same, or use relative paths.