nginx Interoperability Analysis
Luis David Pedrosa
luis.pedrosa at usc.edu
Thu Sep 18 08:24:50 UTC 2014
Hello everyone,
I'm Luis Pedrosa and I a researcher and graduate student at the
University of Southern California. My research involves using program
analysis techniques on protocol implementations to automatically find
interoperability issues. The idea is to automatically find scenarios
that lead, for example, a client to send something to a server that is
somehow rejected as an invalid message. The point being to either find
bugs in the code that can be fixed or, more importantly, to find
ambiguities in the standard that should clarified.
To evaluate our tool we analyze open-source protocol code and find
potential bugs. I've been analyzing the SPDY protocol using the
spdylay library as a client and nginx as as a server. We found a few
situations where interoperability breaks down between these two, and
would like to hear from the nginx-devel community on whether these
issues are legitimate and relevant. The issue we found are:
- nginx doesn't support "HTTP/0.9" in the "version" header and rejects
the message as a bad request. Actually, I believe it looks for
anything starting with the following pattern: "HTTP/[1-9]". Is there a
reason for HTTP/0.9 to be rejected, while HTTP/3 onwards would be
accepted, especially since nginx does support HTTP/0.9 outside of
SPDY? spdylay doesn't understand the semantics of the header and let's
anything through. The SPDY draft doesn't really offer any insight into
allowed values here other than the example "HTTP/1.1". Should the SPDY
specification be more clear about the semantics here?
- When parsing the path header, nginx must un-escape percent-encoded
characters (e.g. %20 for space). If the path has a %, followed by
something other than two hexadecimal digits (e.g. path="/%%"), nginx
rejects the message as a bad request. Again, spdylay doesn't care
about the semantics of the header. The SPDY draft refers to RFC-3986
for URIs, which does require two hex digits after a percent. In your
opinion, is automatic character escaping and percent encoding
something the client should do, or is this something that should be
left up to whoever made the link in the first place?
- We also found a deeper issue with correctly formatted
percent-encoded characters. It turns out that nginx explicitly blocks
the correctly encoded NUL character (%00) in the path header. As
before, spdylay doesn't care about such things. RFC-3986 explicitly
allows the decoder to reject this character if it does not want to
handle it. Is there a particular reason for nginx to reject this
encoded character, or is it just a can of worms no one wants to open?
- nginx does not allow either the carriage-return ('\r') or the
line-feed ('\n') character in header values. spdylay doesn't check for
this. I don't believe the SPDY draft mentions this as a problem, but
if this were pure HTTP the constraint would make sense as it would
start the next header. Should the SPDY draft mention something about
handling this corner case?
- As nginx parses the path, it keeps track of the hierarchy depth and
rejects requests that try to break out of the web-root directory
(path="/a/../../"). This is a sane security policy, as this was a huge
problem in the early years of the web. spdylay doesn't understand the
semantics of the path header and lets anything through. I was
surprised to see this being handled in parsing code. Is there a reason
that this would be handled as a bad request, instead of a permission
issue? Is it just such a bad idea that the sooner it's shot down the
better?
- nginx doesn't allow the TRACE method header value. This is a
perfectly fine message to send, so spdylay let's it out. Is there a
particular reason why such a simple HTTP method isn't handled?
Please let me know what you think of these issues and of the ability
to find them mostly automatically.
Thank you.
Best regards,
Luis D. Pedrosa
More information about the nginx-devel
mailing list