Breaking with protocol

Are you or your users are getting a “This page contains both secure and nonsecure items” message in Internet Explorer?

This page contains both secure and nonsecure items: Do you want to display the nonsecure items?

You might mistakenly believe that it is a problem isolated to IE, but if you check the bottom right corner of Firefox you’ll see that all is not well there either:

The issue here is a simple one to understand. The browser is rendering a page over SSL denoted by the https:// protocol in the address bar. However, there are elements within that page that are being served via the nonsecure http:// protocol. These elements may be images, frames, stylesheets, javascript, etc

By now you might be asking how you can serve up resources to visitors over either protocol without maintaining separate sites or stylesheets. The most obvious and easiest way to accomplish this has been to change any absolute URLs to relative paths.

Change:


<img src="http://www.example.com/images/header.png" />
div#header {
  background-image: url(http://www.example.com/images/header.png) no-repeat;
}

To:


<img src="/images/header.png" />
div#header {
  background-image: url(/images/header.png) no-repeat;
}

However, what happens if you maintain your static files on a separate server or sub-domain and you can not link to them using a relative URL? Is it possible to still maintain a single stylesheet (assuming, of course, that both sites are secured by trusted certificate)?

I think so, yes. You can link to things in a sudo-absolute manner by omitting the leading protocol. For example:


<img src="//www.example.com/images/header.png" />
div#header {
  background-image: url(//www.example.com/images/header.png) no-repeat;
}

I’ve only done limited testing on IE and Firefox thus far, but it seems to work fine. I’m curious to hear anyone’s thoughts on the pros and cons of this method. Interestingly, it’s difficult to find anything that been written about this on th web. All the keywords I try bring up nothing but whitepapers and RFCs.

Update: 01.23.2008 5:40pm

Ok, so after digging and digging and digging I’ve finally found what I’m looking for! This behavior is, in fact, in the HTTP 1.1 standard as specified in RFC 2068 and RFC 2396:


   URIs in HTTP can be represented in absolute form or relative to some
   known base URI, depending upon the context of their use. The two
   forms are differentiated by the fact that absolute URIs always begin
   with a scheme name followed by a colon.

          URI            = ( absoluteURI | relativeURI ) [ "#" fragment ]

          absoluteURI    = scheme ":" *( uchar | reserved )

          relativeURI    = net_path | abs_path | rel_path

          net_path       = "//" net_loc [ abs_path ]
          abs_path       = "/" rel_path
          rel_path       = [ path ] [ ";" params ] [ "?" query ]

When specifying a relativeURI, the most common usages are the abs_path and rel_path like the following:


/* abs_path */
div#header {
  background-image: url(/images/header.png) no-repeat;
}
<!-- rel_path -->
<img src="images/tree.jpg" alt="Oak" />

However, using net_path to optionally include the http: or https: is apparently perfectly valid as well. It’s so obscure or rarely used that a Google search for “net_path” will suggest that you correct your search to “set_path”.

It looks funny and it feels wrong, but it works.

  • http://www.silverspider.com Alex

    Interesting solution Ryan. This doesn’t seem like it should work though. Without the http, the browser has no idea which protocol to use to get the linked object. It could be a mailto or gopher… Seems brittle.

  • http://drhayes.tumblr.com David

    I gotta agree with Alex. What about some server-side processor that “forwards” non-secure assets through a secure gateway? The server would still take the SSL-connection hit… but users wouldn’t get that warning and you’d still be indicating protocol. What do you think?

  • Ryan Joy

    @Alex: I know it’s crazy and it’s definitely an edge case, but it does seem to work reliably. The browser knows which protocol to use because it will fall back on whichever protocol the page is served from. Nothing is served from mailto, so that’s not applicable. As for gopher… ummm, we really shouldn’t be mixing protocols anyway. HTTP and HTTPS are one and the same, albeit using different ports.

    @David: On a high traffic site, the server hit could be a big one.

    PS – Does anyone else try to ‘click’ that screen capture of the confirmation box each time this page loads? I do.

  • http://www.silverspider.com Alex

    Well, that’s where the brittle part comes in – you’re trusting that the browser will guess correctly. As for gopher and the like, you aren’t mixing protocols, there are multiple transfer protocols to ensure the right one is used, for example using ftp:// to download large files is recommended.

    I agree with David, this should be solved on the server-side, relying on improper markup and browsers to make the right choice is a recipe for pain and remorse the likes of which humanity has not seen for a millenna. Or at the very least a really annoying afternoon on the phone with an angry client or boss.

  • Ryan Joy

    Nothing is served to a web page from an ftp:// protocol. In other words, those requests are handled differently anyway. If I were to try to use an ftp url as the src of an image, users would probably be prompted to download said image instead of it rendering in the document.

  • Matt Semar

    Wow, nothing brings clarity to an issue like a BNF grammar. Good job digging through the RFCs.

  • http://drhayes.tumblr.com David

    That is totally wild. Hard to argue with the standards. ( =

    And yes, indeed, *even though I’m on a Mac*, the page came up and I moved the cursor to click OK. Stimulus-response, stimulus-response…

  • Warren

    From a security standpoint loading images from a non secure source is not secure since image files can be exploited so the end user really has no clue. Incurring the additional overhead is the correct thing to do from a best practices standpoint.

    Furthermore, I would advise not serving from 2 web servers from the end user perspective. If you want to physically host on 2 separate locations use a “proxy” server to handle the certificate and the like and present a virtual web server.

    Though I have been aware of usage of net_path I never realized that it wasn’t common knowledge. I guess that would explain why so many secure sites don’t do this right. Hopefully, the search engines will pick up this blog post of yours.

    If you are intending to share javascript between subdomains you’ll need to alter the document domains so they are the same. Personally, I recommend not going down this path unless you don’t have a choice since it will make using third party javascript more difficult.

  • http://www.silverspider.com Alex

    Damn, good find Ryan! I stand corrected. I’m not sure I’ll ever use a net_path based relative URI, but it’s very handy to know that it’s an option.

    Oh, and a quick note about the protocols bit in my earlier comment – I wasn’t saying that the image would be served up via FTP, merely that the browser knows to run a specific action when it encounters specific protocols, like open an FTP client, a news reader or your e-mail program. My now-out-dated thinking was that the browser needed the protocol in order to determine which action to take.

  • http://www.statesman.com Christian

    It’s taken me a couple of days to get to this … but thank you, Ryan. You, of course, understand the problem as you’ve worked with the very site I am working on. This is definitely and interesting solution and I have just the place to try it out. I’ll let you know how it goes.

  • Christian

    Well, this has tested out well and I’m fairly certain we’ll do this. Thanks again, Ryan.