facebook/proxygen

Websocket Key Mismatch

SteveSelva opened this issue · 5 comments

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?

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?

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

Apologies you didn't get a prompt reply here -- honestly I can never keep all the websocket key business straight in my head. Are you saying something is stripped on the downstream request that needs to be resent upstream?

Closing due to lack of engagement. Please reopen if you still need assistance with WebSockets.

Apologies, I didn't see your message. And I have handled the WebSocket just by converting it into AsyncSocket, so it just works like a HTTP Connect Request.