Seitenanfang

Where is your HEAD?

Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.


Most people would answer "on top of my neck" but that's not always right. Actually, most heads are above their bodies but not every head has a body - which usually is no problem. Trouble starts when someone asks for a head without a body. Headhunters do (but I don't care about them, at least within this post) and web-browsers also do from time to time.

You might have noticed: I'm talking about HTTP requests and responses, not human bodies and not about the French revolution (which has been a headless time for some people, but that's another story).

HTTP GET requests usually don't contain any body, POST requests do but both are handled well by (most) scripts.

HTTP responses without body are quite common in case of redirections (status code 301 and 302) and sometimes as reply to access violations or hacking attempts.

 

But HTTP isn't just GET and POST, there is a third common request method: HEAD. Most webservers support (and allow) - the other methods are usually not supported or disabled by default.

Most webservers support HEAD requests - but very few scripts do. Most scripts accept their parameters using GET and POST and don't make any difference between both of them - but it's the same with HEAD requests.

Imagine an unsubscribe link from your favorite mailing list which unsubscribes your email address without asking for confirmation. Now imagine a wanna-be-"intelligent" mail client who wants to know (for any unknown reason) if a link is reachable - and sends a HEAD request to check. Just read a mail - and the client's HEAD request automatically unsubscribes you without any notice because the mailing list server script doesn't ever check if the request is GET, POST - or HEAD.

Imagine you requested a quote from your favorite supplier and the mail might contain a "1-click-order" link.

What if your provider is using a proxy server? The server might send a HEAD request before sending out your real GET request. You might get a password-reset link but the link is outdated because the proxy's head request already used this one-time link and your GET request was too late.

You might think that these are rare conditions, but that's not true. I have been ignoring the request method for ages until I checked the logs of a project (for some other reason) and found a reasonable number of HEAD requests unsubscribing people which usually didn't want to be unsubscribed.

We tracked down some of them and both samples above seem to happen each day!

Avoiding these problems is very simple: Check the request method and return something valid but not secure for HEAD requests. CGI scripte could check the REQUEST_METHOD environment variable:

#!/usr/bin/perlif ($ENV{REQUEST_METHOD} eq 'HEAD') {   print "Content-type: text/html\n\nHEAD requests are not supported for this URL\r\n\r\n";   exit;}
Other frameworks might need other ways to check for HEAD requests and to skip processing for the current request. PHP has a $_SERVER['REQUEST_METHOD'] variable (which has been renamed at least once between PHP versions but I guess PHP developers are used to changing core functions).

Most projects are using a framework or at least common files which are processed on every incoming request - they're a very good place for a request method check if they run before the called script or function might do anything harmful. The HEAD request protection has been added just before the parameter parsing in the project where I discovered the issue.

The Perl Dancer framework requires each URI to register for GET or POST requests - and should be safe from HEAD problems.

 

5 Kommentare. Schreib was dazu

  1. Dancer sets up a HEAD route when a GET route is set up, so it has the same problem.

  2. Sebastian

    Thanks.

  3. If you design such that your GET requests are idempotent, they wouldn't change state. In the examples you cite, perhaps the GET/HEAD requests should return a page to get confirmation which would be submitted via POST.

  4. You are violating the HTTP spec several times. You SHOULD NOT (see §9) unsubscribe someone with GET/HEAD. You must not return a "Successful 2xx" series status code ("exit;") with your error document, but must indicate a Client Error 4xx; see §10.4.6 for the appropriate one. Lastly, disallowing the HEAD method for no good reason and delivering a message body in any case - although proscribed by §9.4 - breaks assumptions built into lots of Web software, such as caches.


    To expound on Michael's comment: change your code to always use the POST method for side-effects, make usage of GET "safe" (§9.1.1), then reenable HEAD.

  5. Sebastian

    It's not (only) me - most scripts don't care if they're called using GET or POST. Looks like reality doesn't match the specs, did it match anytime in the past?

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>