-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
net/http: expect: 100-continue
handling is broken in various ways
#67555
Comments
Change https://go.dev/cl/587155 mentions this issue: |
Disable three 100-continue tests that aren't exercising the intended behavior because they don't set ExpectContinueTimeout. The tests are flaky right now; setting ExpectContinueTimeout makes them consistently fail. Set ExpectContinueTimeout and t.Skip the tests for now. Fixes #67382 For #67555 Change-Id: I459a19a927e14af03881e89c73d20c93cf0da43e Reviewed-on: https://go-review.googlesource.com/c/go/+/587155 Auto-Submit: Damien Neil <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
Change https://go.dev/cl/591255 mentions this issue: |
When sending a request with an "Expect: 100-continue" header, we must send the request body before sending any further requests on the connection. When receiving a non-1xx response to an "Expect: 100-continue" request, send the request body if the connection isn't being closed after processing the response. In other words, if either the request or response contains a "Connection: close" header, then skip sending the request body (because the connection will not be used for further requests), but otherwise send it. Correct a comment on the server-side Expect: 100-continue handling that implied sending the request body is optional. It isn't. For #67555 Change-Id: Ia2f12091bee697771087f32ac347509ec5922d54 Reviewed-on: https://go-review.googlesource.com/c/go/+/591255 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]>
@gopherbot please open backport issues. This is a significant bug with no workaround. |
Backport issue(s) opened: #68199 (for 1.21), #68200 (for 1.22). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://go.dev/wiki/MinorReleases. |
Change https://go.dev/cl/595096 mentions this issue: |
Change https://go.dev/cl/595235 mentions this issue: |
…pect-100-continue requests When sending a request with an "Expect: 100-continue" header, we must send the request body before sending any further requests on the connection. When receiving a non-1xx response to an "Expect: 100-continue" request, send the request body if the connection isn't being closed after processing the response. In other words, if either the request or response contains a "Connection: close" header, then skip sending the request body (because the connection will not be used for further requests), but otherwise send it. Correct a comment on the server-side Expect: 100-continue handling that implied sending the request body is optional. It isn't. For #67555 Fixes #68199 Change-Id: Ia2f12091bee697771087f32ac347509ec5922d54 Reviewed-on: https://go-review.googlesource.com/c/go/+/591255 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> (cherry picked from commit cf501e0) Reviewed-on: https://go-review.googlesource.com/c/go/+/595096 Reviewed-by: Joedian Reid <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
…pect-100-continue requests When sending a request with an "Expect: 100-continue" header, we must send the request body before sending any further requests on the connection. When receiving a non-1xx response to an "Expect: 100-continue" request, send the request body if the connection isn't being closed after processing the response. In other words, if either the request or response contains a "Connection: close" header, then skip sending the request body (because the connection will not be used for further requests), but otherwise send it. Correct a comment on the server-side Expect: 100-continue handling that implied sending the request body is optional. It isn't. For #67555 Fixes #68200 Change-Id: Ia2f12091bee697771087f32ac347509ec5922d54 Reviewed-on: https://go-review.googlesource.com/c/go/+/591255 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> (cherry picked from commit cf501e0) Reviewed-on: https://go-review.googlesource.com/c/go/+/595235 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Joedian Reid <[email protected]>
From the security team related to this issue: The net/http HTTP/1.1 client mishandled the case where a server responds to a request with an "Expect: 100-continue" header with a non-informational (200 or higher) status. This mishandling could leave a client connection in an invalid state, where the next request sent on the connection will fail. An attacker sending a request to a net/http/httputil.ReverseProxy proxy can exploit this mishandling to cause a denial of service by sending "Expect: 100-continue" requests which elicit a non-informational response from the backend. Each such request leaves the proxy with an invalid connection, and causes one subsequent request using that connection to fail. Thanks to Geoff Franks for reporting this issue. This is CVE-2024-24791 and Go issue https://go.dev/issue/67555. |
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
As the CLs are in and the backports are done, is there anything else needed for this issue, or we can close this? Thanks. |
This is a follow-up to #67382. See that issue for some prior discussion. (That issue is also full of watchflakes reports, so I'm letting it be about the test flakiness. This issue is about the underlying problem.)
An HTTP/1 or HTTP/2 client can send an
Expect: 100-continue
header in a request to indicate that it might not send the request body until the server asks for it. The client is permitted to send the request body anyway, either immediately or after a delay.A server may respond to a
Expect: 100-continue
request with an informational 100 status, indicating that it would like the client to send the request body. A server may also respond with a non-1xx status, without waiting for the request body.For HTTP/1, a client must send the body for a request or close the connection. If a client sends a
Expect: 100-continue
request and receives a non-1xx response from the server, it still needs to finish sending the current request's body before sending any further requests on the connection.For HTTP/2, a client can reset a request's stream and continue to use the connection without sending the body.
This issue is about how our client and server implementations handle the case of a server responding to an
Expect: 100-continue
request with a non-1xx response.Client: If we receive a non-1xx response to an
Expect: 100-continue
request, should we send the request body on the assumption that the server might want it? Or should we assume that receiving response headers from the server indicates that the server didn't need the body? Should we modify this behavior for different response codes? A 200 OK might indicate that the server is going to use the request body, but a 403 Forbidden probably does not. Should we modify this behavior based on the presence or absence of aConnection: close
header in the response? (Note that for HTTP/1 requests, if we do not send the request body, we may not reuse the connection for further requests.)Server: When handling an
Expect: 100-continue
request, we automatically send a 100 Continue response if the server handler reads from the request body. What should we do if the server handler callsWriteHeader
to send a non-1xx response, and then reads from the request body? Should we assume the server handler knows what it's doing, and trust that the client is going to send us a request body? Or should we return an error from the body read?Our current behavior is inconsistent and occasionally wrong.
The HTTP/1 client does not send the request body if it receives a non-1xx response before
ExpectContinueTimeout
expires. This can leave the connection in an invalid state. (Server responds with a non-1xx response and attempts to read the request body; client reuses the connection for another request without sending the body.)The HTTP/2 client always sends the request body after
ExpectContinueTimeout
, regardless of whether it has received a non-1xx response or not. If the server is trying to read the body, it will eventually get it, but only after a timeout.Both HTTP/1 and HTTP/2 servers appear to permit reading from a request body even after sending a non-1xx response (and no 100 Continue response).
I'm not certain yet what we should be doing, but at a minimum:
ExpectContinueTimeout
timer after receiving a non-1xx response. It should either send or not send the request body, but it shouldn't keep delaying.Expect: 100-continue
request body after sending response headers gets an error or not.The text was updated successfully, but these errors were encountered: