Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http.server.BaseHTTPRequestHandler: Unhelpful error message when receiving HTTPS requests #109765

Open
behnam opened this issue Sep 22, 2023 · 0 comments
Labels
stdlib Python modules in the Lib dir

Comments

@behnam
Copy link

behnam commented Sep 22, 2023

Using python3 -m http.server to quickly start a local web-server is a common practice for people learning Python, web programming, or some other coding skills. The output of the command is often something like:

Serving HTTP on :: port 8000 (http://[::]:8000/) ...

If the user then tries to hit that server from their browser, and the browser is configured to use HTTPS by default—which is becoming more common every day—then the std out/err will dump some binary garbage from the TLS handshake:

::1 - - [22/Sep/2023 15:05:09] code 400, message Bad request version ('êê\x13\x01\x13\x02\x13\x03À+À/À,À0̨̩À\x13À\x14\x00\x9c\x00\x9d\x00/\x005\x01\x00\x01\x93JJ\x00\x00\x00-\x00\x02\x01\x01Di\x00\x05\x00\x03\x02h2\x00\x12\x00\x00\x00\x1b\x00\x03\x02\x00\x02\x00\x05\x00\x05\x01\x00\x00\x00\x00ÿ\x01\x00\x01\x00\x00')
::1 - - [22/Sep/2023 15:05:09] "üáЪ��|.�:áÞ-�»l6åAZW¹Ê#M2Hä�¯ �Ó§Ú��¹óÓ
                                                                        ��g¥Ç�µdeÚv�õÇ\ êêÀ+À/À,À0̨̩ÀÀ��/5�JJ-Dih2ÿ" 400 -
::1 - - [22/Sep/2023 15:05:09] code 400, message Bad request version ('S')
8OÇ  þ1Ñ[ððø1ZìW'*0¡Íh¤fµM@�Ô�úßÉ�»Õ ººÀ+À/À,À0̨̩ÀÀ��/5�zz3+)jj S" 400 -

This is because of the BaseHTTPRequestHandler class trying to "parse" the first line of the input regardless of it following the Request-Line pattern of the HTTP RFC or not. Here's the line doing so:

words = requestline.split()

As we can see in specs (RFC 2616, RFC 7231), we have

request-line   = method SP request-target SP HTTP-version CRLF

where

method         = token

token          = 1*tchar

tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
                    / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
                    / DIGIT / ALPHA
                    ; any VCHAR, except delimiters

and VCHAR is defined as "any visible [USASCII] character".

This means, it's actually easy to check the first character of the line to see if there's any chance of it starting with a method token or not, and if not, bail with a more helpful error message.


One option would be to raise an error on anything that looks like a non-token-starting line, like, checking the first character against the tchar list.

Another stronger option—meaning, it can produce more helpful error message—would be to check the first byte for the explicit value matching a TLS Handshake type, as defined in (RFC 5246)[https://datatracker.ietf.org/doc/html/rfc5246#section-7.4]:

      enum {
          hello_request(0), client_hello(1), server_hello(2),
          certificate(11), server_key_exchange (12),
          certificate_request(13), server_hello_done(14),
          certificate_verify(15), client_key_exchange(16),
          finished(20), (255)
      } HandshakeType;

Of course, the latter would be easier to maintain if reusing some existing code from the available libraries.


Regardless of the exact check, the failure result could be done with something along the lines of:

self.send_error(
    HTTPStatus.BAD_REQUEST,
    "Request starts with invalid characters; possibly binary from a TLS handshake. "
    "Try accessing the server with HTTP protocol.")
return False

However, we may need to do extra work outside of that function to reduce the number of errors from 3-4 to exactly 1.

How does this sound to everyone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir
Projects
None yet
Development

No branches or pull requests

2 participants