Postel’s Law and network security
March 22, 2012  

Postel’s Law, which I’ve written about before, goes like this:

Be conservative in what you do, be liberal in what you accept from others.

The graybeards tell me that Postel’s Law was an important engineering guideline for the development of the Internet. To me it seems not only an example of pragmatic engineering but a necessary property of network protocols, which are naturally designed and implemented in a distributed fashion. If you are bootstrapping a network and its protocols with collaborators across the globe, and you find a mismatch between your implementation and another’s, you aren’t going to stop the network, call them on the phone, get them to fix their bug, and restart—you are going to bumble on as best you can. There aren’t many successful network protocols whose implementations ignore Postel’s Law.

That said, any protocol implemented according to Postel’s Law is going to fall prey to an immediate corollary that has unfortunate security implications:

Corollary: Everyone is liberal in a different way.

Here are a couple of examples.

NUL characters in SSL certificates

In 2009 or so, Marlinspike noted that SSL certificate authorities were signing certificates for domains containing the NUL (ASCII 0) character. For example, consider this domain where 0 denotes NUL:

gmail.com0.ev.il

To an SSL certificate authority, this may look like a subdomain that should be “owned” by the ev.il domain. If so, they will happily issue an SSL certificate for the subdomain to the owner of ev.il. This is actually a liberal treatment of domain names in the sense of Postel, because domain names aren’t supposed to include NUL.

Now consider a browser trying to reach https://gmail.com/. Its communication could be intercepted by agents of ev.il (there are lots of ways this can happen, but the details are not important here). That’s fine so far, because SSL should detect this. However, ev.il has a certificate for gmail.com0.ev.il, which it gives to the browser. The browser, however, interprets the certificate as a certificate for gmail.com, because it is using NUL as a string terminator (common practice in programming languages like C), so ev.il has succeeded in impersonating gmail.

The browser is interpreting the bogus domain name liberally, in the sense of Postel, but the browser’s “liberal” is different than the certificate authority’s “liberal”.

HTTP request splitting

Here’s a second example, derived from one by Watchfire:

    POST /form.html HTTP/1.1
    Host: example.com
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 0
    Content-Length: 44

    GET /good HTTP/1.1
    Host: example.com
    Bla: GET /evil HTTP/1.1
    Host: example.com

This looks like a sequence of HTTP requests (the messages your browser sends to web sites to retrieve content). However, something is strange because the first request has two Content-Length fields, when it should have at most one. If we want to be liberal like Postel, there are a couple of ways to handle this. One way is to believe the first Content-Length header, in which case we get two requests,

    POST /form.html HTTP/1.1
    Host: example.com
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 0
    Content-Length: 44

and

    GET /good HTTP/1.1
    Host: example.com
    Bla: GET /evil HTTP/1.1
    Host: example.com

Here we are posting to /form.html and getting the resource /good.

A second way to be liberal is to believe the second Content-Length header, in which case, we get two different requests,

    POST /form.html HTTP/1.1
    Host: example.com
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 0
    Content-Length: 44

    GET /good HTTP/1.1
    Host: example.com
    Bla: 

and

    GET /evil HTTP/1.1
    Host: example.com

In this case we are posting to /form.html again, though the contents of the posting are different (the posting includes the GET /good); and we are getting the resource /evil. (In a real attack, /evil would be a well-chosen request that would cause trouble for the web site.)

Once again, two ways of being liberal. This can be a problem when you have two programs working together, each of which is liberal in a different way. A common example is a proxy that sits in front of a web site, filtering requests, and throwing out any “bad” requests that it sees.

Here if the proxy sees our input and uses the first interpretation, it will let it through. If the web site uses the second interpretation, it will be exploited, and we will have defeated the proxy’s protection.

Script injection

As a final example, I’ll use the current most-reported security vulnerability, the script injection. A script injection happens when a web site serves up input provided by its users. Facebook is one example (of many). Most of the web pages you look at on Facebook contain content provided by its users—after all, that’s the whole point of Facebook. Script injection happens when a user provides the site with content in such a way that the resulting web page includes a script of the user’s choice. This script will be executed in the browser of other users who view the page.

Script injection is common but complicated. I’m not going to spell out all of the details (see my BEEP project if you want to know more), but one of the complications is relevant to Postel’s Law. Namely, the main defense against script injection is for the web site to be careful with user input: it should filter out user input that includes scripts.

Of course, this requires knowing exactly what constitutes a script. And browsers do not agree on this. Browsers, famously, have incompatibilities.

For example, most browsers think that this snippet of HTML

    <img src=java
    script:alert(0)>

does not contain a script. However, some browsers will treat it as a script, essentially treating it as if it were this correct snippet:

    <img src=javascript:alert(0)>

Something similar happens for the following snippet:

    <img """><script>alert(0)
    </script>">

In short, the answer to the question of whether a bit of user input includes a script depends on the browser—there is no one answer. Each browser, and each version of a browser, may have a different answer; they can all be liberal in a different way. This is one of the major hurdles for any defense against script injection.

Summary

It is very hard to build two independent implementations of a network protocol which behave identically (in fact the point may well be that they behave differently, e.g., one may be faster). Whenever this happens, the implementations still need to interact, and they do so by Postel’s Law. If you are interested in finding (and preventing) attacks on protocols, one of the best places to start looking is somewhere that the implementations are liberal in different ways.