facebook / proxygen

A collection of C++ HTTP libraries including an easy to use HTTP server.
Other
8.03k stars 1.47k forks source link

Websocket Key Mismatch #483

Open SteveSelva opened 3 months ago

SteveSelva commented 3 months ago

In Downstream, in HTTP1xCodec.cpp file, the websockAccept is generated from the websockAcceptKey sent from the Browser.

But in Upstream, an error message is thrown and the connection is terminated:

E20240206 16:59:09.517776 16080 HTTP1xCodec.cpp:1155] Mismatch in expected ws accept key: upstream: i3nI98Wx41+xdf2LZ91PdtmsuZ8= expected: 
E20240206 16:59:09.517776 16080 ProxyHandler.cpp:267] onServerError():what="Error parsing message: the on_headers_complete callback failed", direction=0, proxygenError=ParseHeader, codecStatusCode=-1, httpStatusCode=0

I think the expected Accept value for Websocket is not sent from Downstream to Upstream, so the expected value(proxygen::HTTP1xCodec::websockAcceptKey_) is empty in the error log message.

Proxygen.v2023.10.30 HTTP1xCodec.cpp LineNo.1147

  const std::string& upgrade = hdrs.getSingleOrEmpty(HTTP_HEADER_UPGRADE);
  if (kUpgradeToken.equals(upgrade, folly::AsciiCaseInsensitive())) {
    msg_->setIngressWebsocketUpgrade();
    if (transportDirection_ == TransportDirection::UPSTREAM) {
      // response.
      const std::string& accept =
          hdrs.getSingleOrEmpty(HTTP_HEADER_SEC_WEBSOCKET_ACCEPT);
      if (accept != websockAcceptKey_) {
        LOG(ERROR) << "Mismatch in expected ws accept key: "
                   << "upstream: " << accept
                   << " expected: " << websockAcceptKey_;
        return -1;
      }
    } else {
      // request.
      // If the websockAcceptKey is already set, we error out.
      // Currently, websockAcceptKey is never cleared, which means
      // that only one Websocket upgrade attempt can be made on the
      // connection. If that upgrade request is not successful for any
      // reason, the connection is no longer usable. At some point, we
      // may want to change this to clear the websockAcceptKey if
      // the request doesn't succeed keeping the connection usable.
      if (!websockAcceptKey_.empty()) {
        LOG(ERROR) << "ws accept key already set: '" << websockAcceptKey_
                   << "'";
        return -1;
      }
      auto key = hdrs.getSingleOrEmpty(HTTP_HEADER_SEC_WEBSOCKET_KEY);
      websockAcceptKey_ = generateWebsocketAccept(key);
    }
  }

How to fix this issue?

SteveSelva commented 3 months ago

I am using Proxygen as a MITM proxy server. While establishing a WebSocket connection from downstream to upstream, this error occurred. Here, the websocketAcceptKey is stored in downstream from the WebSocket Request. While forwarding the WebSocket Request to upstream, it didn't copy the key and didn't generate the websocketAcceptKey, but its checking whether the websocketAcceptKey is matching the key received from the upstream, which results in this error.

Does Proxygen supports WebSocket over Proxy Communication or the implementation is wrong?

SteveSelva commented 3 months ago

@afrind @jbeshay Can you help with this issue pls.