Browsers try their best to protect users from the evils of the internet, but some times their eager kills good use cases all the same. The “mixed content warning” that IE and Firefox throws when you reference a non-SSL asset from an SSL page is one of those cases.
The problem is that browsers don’t like caching SSL content. So when you have an image or a style sheet on SSL, it’ll generally only be kept in memory and may even be scrubbed from there if the user is low on RAM (though you can kinda get around that).
Even when you do your best to limit the number of style sheets and javascript files and gzip them for delivery, it’s still mighty inefficient and slow to serve them over SSL every single time the user comes back to your site. Even when nothing changed. HTTP caching was supposed to help you with that, but over SSL it’s almost all for naught.
Now I understand why SSL content is not kept on a disk cache. You don’t want the financial-results-2008.png lying around on a public computer that you thought was safe to use because of SSL.
This is why it would be ever so wonderful if you could refer to a non-SSL asset from an SSL page. That way you could say “this stuff is private, don’t share it” when serving over SSL and at the same time take advantage of HTTP caching for things that pose no security risk, like drag_handle.gif.
But oh no. If you try to do that with IE, you’ll get a “mixed content warning” that’ll scare the bejesus out of your users, so that won’t go. On Firefox, you’ll often (depending on settings) get the same warning if you try to serve JavaScript or style sheets like that.
Only Safari stands out as the hero with no mention of “mixed content warning”. So please, IE and Firefox, can you learn from Safari and kill it too? Then we wouldn’t have to adjust our asset rules depending on the user agent and everyone would be able to enjoy the extra speed of properly caching assets.
Note: There’s a reasonable argument for warning on JavaScript includes as man-in-the-middle attacks can do nasty things, but that’s not true for CSS (on anything but IE) or images
Jason Cale
on 27 Nov 08Totally, this is really annoying ..
Like the gist though, I might use that in one of the apps I’ve maintaining.
me
on 27 Nov 08If some attacker is able to either tamper with Javascript or stylesheet files he can effectively also tamper with the other content on your page (e.g. by modifying the DOM). So its either all or nothing. Either all of your elements are served using SSL, then you are secure. Or you load some JavaScript or stylesheet files from a plain HTTP connection, then you aren’t secure anymore. A better option would be to be able to “allow” the browser to cache files, even though they are served using SSL.
Paul Leader
on 27 Nov 08@me
Agreed. In addition, IE can execute javascript from CSS (yup, it’s insane) and I have seen a number of attack sites that use this technique.
In addition, there is an increased risk that cookies will be exposed. If people don’t use secure cookies reliably, session cookies may leak out though the insecure requests.
One last thing: don’t forget that there have been attacks in the past that have relied on graphics processing code. Also, you can always send alternative content instead of the .gif, just because it looks like a graphics file, doesn’t mean it is, or is harmless.
DHH
on 27 Nov 08Paul, the JS in CSS problem seems to be affecting only IE. It’s pretty nuts that IE allows that! They should stop ;)
Also, if you refer to a gif in img src=””, I don’t know of any vectors that can cause that to execute code. Do you? May well be if you access the image straight on and just send something else, but not if it’s part of a html referral.
Jim Fiorato
on 27 Nov 08There was an issue in IE 6 where you could execute javascript from the meta data of an image… Crazy.
http://kestas.kuliukas.com/JavaScriptImage/
This has since been resolved in IE 7.
Adam
on 27 Nov 08You can execute JavaScript through CSS, so yeah, it makes sense to block it in order to protect from XSS over SSL.
Matthew
on 27 Nov 08The browser doesn’t know what sort of resource it’s requesting, ever. (It may know what it’s supposed to be, but there’s no way to guarantee that’s what it actually is.) Nor does it know whether sensitive data may be being sent as part of the request. Or whether it comes from where it’s supposed to.
So basically any non-encrypted content undoes any benefit from SSL. Sorry, but Firefox gets this one right.
Joshua Paine
on 27 Nov 08IE can’t drop JS-in-CSS without breaking many sites, since we use it to emulate the CSS features available in better browsers.
The real right way to do this is browsers should go ahead and cache SSL content if it has Cache-Control: Public header set. I think there’s talk of enabling that in FF—I’m not sure of the status. Also, if it turns out there’s widespread misapplication of cache-control:public, browsers could cache only that SSL content with cache-control:public and an expiration date set in the far future, which virtually no one has set by accident.
DHH
on 27 Nov 08Matthew, the point is that the application developer will pick the right host for the right type of content. When it needs to be secure, it’s referrenced and served over SSL, when not, it’s over non-SSL.
Also, Firefox actually allows you to serve non-SSL images over SSL without triggering the mixed content warning.
DHH
on 27 Nov 08I do agree that it would be nice to control this by caching headers also, though. But even then you can want to serve over non-SSL to get around the expensive SSL handshake over long distances.
Henrik N
on 27 Nov 08David: “loath” is an adjective that means “reluctant”, “unwilling”; “loathe” is a verb that means “feel intense dislike or disgust for”.
Micheal
on 27 Nov 08David
I believe the way to get around the mixed content warning is to refer to the digital asset in the following way:
”//asset.example.com/test.jpg”
Notice that I left out “http(s):”.
By leaving our the protocol, the browser assumes that if you’re on a SSL page, to serve it as over SSL. If you’re on a non-protected page, to serve it the standard port 80 way.
Hope this helps.
Micheal
Paul Leader
on 27 Nov 08David, as far as IE executing js in CSS, I agree with you, it’s a really dumb design. However you are wrong on most of the rest.
I’ll point you to this example: http://www.techworld.com/news/index.cfm?RSS&NewsID=3565
It’s an old one, but there have been other examples.
I work in the Internet security/fraud field and I can assure you that there are all sorts of esoteric vectors that you can use to attack people over insecure content.
As a case in point, a friend of mine (also a security penetration tester) is a good photographer. One of his photographs was being used by lots of people on MySpace. Rather than just block them he had a little fun. If the referrer was MySpace, he returned a 302 that pointed to the MySpace logout link. If you attempted to view a MySpace page with his link in you got logged out immediately.
There is nothing to say that making an HTTP GET request for a URL ending in .gif will get you an image. And assuming that content like images are safe because it’s “just a gif” is dangerous thinking, there have been several security bugs in graphics libraries, some of which affected all browsers.
If it is going over an unsecured connection it doesn’t matter what you think you are asking for, it’s what I choose to send you that matters.
I suggest you dig out an intercepting proxy (WebScarab is my personal favourite and works on Macs) and have a play around connections. I recommend a dual monitor configuration, it saves switching windows.
Having mixed content on an SSL site will get you an instant fail from most decent security testers. Really, it is one of the easiest ways to hack a site. Generally we recommend that everything is encrypting from the login page onwards. I’ve personally been able to steal sessions because of mixed usage in several systems.
I know it’s a pain, but using SSL in a half-hearted way is worse than not using it at all. You give the impression of security, while not actually being secure.
Paul
GeeIWonder
on 27 Nov 08This is nuts. DHH recommending the security features of the browser that Paypal, banks and security experts everywhere have warned their users off of. Not only that, he’s recommending some of the very ones that are the problem.
Why? Because there’s all kinds of trivial and non-trivial attacks that are more easily implemented with this stuff.
I know, I know… strong positions. Fair enough.
When it needs to be secure, it’s referrenced and served over SSL , when not, it’s over non-SSL.
Except site owner don’t have control over every element that’s loaded with every page. Add caching servers, add plugins, add toolbars… the whole thing becomes impossible for the average user to make intelligent decisions on when some elements on ‘secure’ pages are, by design, not supposed to be handled securely. It also makes nesting target sites under your own a simple matter.
Paul, the JS in CSS problem seems to be affecting only IE. It’s pretty nuts that IE allows that! They should stop ;)
Not only can I execute my scripts, I can change yours too. That’s not an IE-specific issue.
I agree that security can make routine UI tasks seem more annoying. But wait until your security fails, and then you’ve just destroyed your UI experience.
From an instantaneous UI perspective I’d rather just board a plane than go through security too.
Steven Fisher
on 27 Nov 08Secure content loading slowly is not your problem, and I’d appreciate it if you didn’t make it so, and in trying to fix it make a bigger problem mine.
Keep your page secure.
Andrew McCall
on 27 Nov 08SSL to protect confidential information makes perfect sense but I’ve always wondered why it wasn’t possible to use the certificate to sign an asset such as a javascript or a CSS file. That would prove it’s come from a specific location but still allow it to be sent plain old HTTP and cached like normal content. It would also allowing the browsers to stick with an otherwise sensible rule – treat secure content securely.
Jay Levitt
on 27 Nov 08It seems like you’re focused on “code execution” as the only type of attack. And that may well be true for many sites.
But, as someone pointed out above, anyone who can control your stylesheet can control your site. If I go to my bank’s web site, and a man-in-the-middle attack shows me what appears to be an inaccurate balance (through CSS tranforms, dummy images, etc.), that’s still an attack. And if they can visually rewrite the content of a “Your new password is” page, they own my account.
There are plenty of MITM attacks that don’t require any code execution. There’s no such thing as safe mixed content, and I’m surprised that Firefox allows non-SSL images on the same page.
Pieter
on 27 Nov 08@DHH
I’m totally feel the same pain about serving seemingly innocuous content over SSL.
I believe in the far future we may not have this problem anymore. However, it would be irresponsible applying exceptions in the handling of SSL for as long as we have such vulnerable browsers out there, and, more importantly, people coding for those (read: microsoft slave idiots).
However, allowing caching for SSL assets solves 80% of the problem and petitioning for that would lead to much less opposition, that is: it may actually happen! And it would probably be backward compatible as well, with no dirty browser detection exception stuff.
Carey
on 27 Nov 08By the way, IE is removing JavaScript from CSS.
(And I’m with allowing caching with Cache-Control: public.)
Eric
on 28 Nov 08I agree that it is annoying, but as others have stated it’s an integrity not just a privacy issue at stake. I would love to see http cache headers allowed to override the default “no caching” of SSL, but mixed-content is right out as it breaks everything that SSL creates. If the disk cache is already compromised them you are kinda hosed anyways.
Eric
on 28 Nov 08You can also recommend
http://kb.mozillazine.org/Browser.cache.disk_cache_ssl
Which will allow forefox to cache ssl pages.
Pete Shaw
on 28 Nov 08Just FYI you can get Firefox 3 (at least I’m not sure about v2) to cache SSL based non-sensitive assets, as alluded to above add a cache-control: public to the http header (after making sure you’re not doing this for content that is sensitive) and an appropriately long expire /etag etc.
Of course I must stress this means public caches will cache these assets! but this is generally fine for quite of lot of standard site stuff.
Grant Hutchins
on 28 Nov 08Javascript expressions in CSS are being phased out in IE8 Standards Mode.
Rene Dudfield
on 28 Nov 08It’s a security problem to use mixed content. If you don’t understand why, then RTFM.
Read: CSRF, MITM, SSL
pwb
on 28 Nov 08To the people claiming it’s such a big security issue, it’s not like it’s disallowed. It just throws up a warning that no one understands and most click through.
Lunes
on 28 Nov 08Opera does that right too, of course.
dusoft
on 28 Nov 08I wouldn’t use a browser (Safari) that doesn’t warn user when serving not-secured content together with secured content. That’s the way of definitely cancelling any possible detection of changed content.
And if you haven’t seen attack over img src, that doesn’t mean it doesn’t exists. Just google it.
Preshit
on 28 Nov 08If Safari and IE had substituted behaviors, DHH would have still found a way to justify Safari’s behavior. After all, Apple can do no wrong.
Phil Coleman
on 28 Nov 08I prefer my technology dumb. It’s rarely wiser than me – more often than not it’s simply a nanny state – and don’t get me started on spell check!
Jay Levitt
on 29 Nov 08[I posted this a few days ago, but it seems to be lost; if it ends up being a double post, mea culpa.]
@DHH: you seem focused on “code execution” as the form of an attack. But there are plenty of other attacks that become possible when you add insecure elements to an insecure page.
As someone pointed out above, if a man-in-the-middle can modify the CSS, they can modify the displayed page. A page with secure text but insecure CSS is like an old church sign with movable letters. If you can scramble the letters, you can make that sign say an awful lot of things. And I don’t even know any of the newer pseudo-selectors or CSS3 transforms; I imagine they add even greater power.
Images can be replaced with other images, and with CSS, they can be repositioned too; there’s no inherent attribute in your “stock art photo of sunset” that prevents it from being “fake text showing fake bank balance”.
Let’s imagine that my bank, ShadiBank, has a secure web site uses non-SSL images and a non-SSL stylesheet.
Now a MITM Nigerian scammer “demonstrates” that they’ve deposited my lottery winnings, by modifying my apparent ShadiBank balance – and, understandably, wants me to wire that accidental overage right back to them. Page lock: displayed. URL scheme: HTTPS. Page: owned.
Or an escalation attack: “ShadiBank security” calls me up, and says I have to change my password right now, while they wait. I log into ShadiBank (legitimately, via SSL). I select the Change Password page (still legitimate), which would normally let me enter a new password. But the MITM has modified it; it now says “For security, we have chosen your new password at random: xyzzy. Please enter it twice for confirmation.” I do so, and the form fields are secure – but now they know my bank password, because they picked it in the first place.
Point is: Web pages aren’t a series of ASCII bytes. They’re a thing you look at. If you can modify what’s seen, you can execute an attack.
I’m not really sure why Firefox lets you use non-SSL images on SSL pages, but I think it shouldn’t do that, either – the above attack can be done only with images, if the page layout is amenable to it.
Simon Willison
on 01 Dec 08I’m with Firefox on this one. SSL is there to guard against man-in-the-middle attacks. If the HTML page is served up over HTTPS but the images or CSS aren’t, someone in the middle could still mess with the page that I’m viewing. A malicious stylesheet could replace show or hide large chunks of the interface. An image that’s meant to say “submit” could be replaced with one that says “cancel”, or vice versa. The padlock icon is meant to mean “cryptography has prevented anyone from screwing with this page in any way”. Serving assets over HTTP could very easily break that promise.
Jesus A. Domingo
on 01 Dec 08I think this is a necessary “annoyance”. The reasons being the following:
- CSS expression rules - cookie access for javascripts - images can point to malicious URLs
I’d rather be annoyed or scared by the warnings, ‘cause I should be, when it comes to supposed-to-be confidential data.
Maybe a different way of presenting the warning is better? But I’d still keep it as a prompt. I don’t want my browser calling/bringing in things that aren’t potentially secure without asking me first.
Aaron
on 01 Dec 08David,
User ‘me’ was right on – allowing unsecured javascript is the worst thing you can do, because tampering of the javascript will lead to full disclosure and tampering of the page contents – you might as well drop SSL outright at that point.
I understand the performance concern – there is non-sensitive content (disclosure is OK), but to maintain privacy of the other page data, you need to prevent tampering. Digital_signatures without other encryption solve this problem. That’s what we really need here. Authenticated but unencrypted content.
This discussion is closed.