openwrt / uhttpd

[MIRROR] Tiny HTTP server
https://git.openwrt.org/?p=project/uhttpd.git;
9 stars 6 forks source link

uhttpd incorrectly strips `\r`, `\x0b`, and `\x0c` from the beginnings of header values #9

Open kenballus opened 2 months ago

kenballus commented 2 months ago

Description

When uhttpd receives a header field value that begins with any number of \x0b, \x0c, or \x0d bytes, it strips them off. While the RFC does require the stripping of optional whitespace on either side of header values, this includes only SP and HTAB bytes.

Expected Behavior

The RFCs permit two behaviors:

  1. Reject the request, since these characters are not permitted within header values.
    • AIOHTTP, Apache, Deno, FastHTTP, Go net/http, H2O, HAProxy, Hyper, Hypercorn, Jetty, Libevent, Lighttpd, Mongoose, Netty, Nginx, Node.js, Passenger, Puma, Tomcat, Uvicorn, Waitress, and WEBrick do this.
  2. Translate the \x0d into SP, then process the request, appropriately stripping SP bytes (including those just created) and allowing \x0b and \x0c to stay in the value.
    • Libsoup, LiteSpeed, and Twisted do this.
stokito commented 2 months ago

Why would a header contain anything except of alphanumeric, hyphen and underscore? It may be printed in logs or shown on UI without escaping so a header mustn't contain anything unusual. Spec this allows i.e. not forbids - ok. But a browser newer sends such headers

kenballus commented 2 months ago

Why would a header contain anything except of alphanumeric, hyphen and underscore? It may be printed in logs or shown on UI without escaping so a header mustn't contain anything unusual.

There are a few other characters commonly used in header values. For example, double quotes are used around parameters in media-type header values like Content-Type. Still, I agree with your larger point, which is that CTL characters other than SP and HTAB don't belong in HTTP header values.

When a header is received that makes use of these characters, it's probably indicative of malicious behavior (i.e., someone trying to exploit parsing differences between uhttpd and a downstream gateway). For that reason, it's probably worth implementing option 1 over option 2.