diff --git a/lib/src/HttpServer.cc b/lib/src/HttpServer.cc index 72431db4c1..a9b1aa42db 100644 --- a/lib/src/HttpServer.cc +++ b/lib/src/HttpServer.cc @@ -47,6 +47,7 @@ using namespace drogon; using namespace trantor; static inline bool isWebSocket(const HttpRequestImplPtr &req); +static bool isValidWebSocketKey(std::string_view key); static inline HttpResponsePtr tryDecompressRequest( const HttpRequestImplPtr &req); static inline bool passSyncAdvices( @@ -736,6 +737,14 @@ void HttpServer::websocketRequestRouting( std::function &&callback, WebSocketConnectionImplPtr &&wsConnPtr) { + if (!isValidWebSocketKey(req->getHeaderBy("sec-websocket-key"))) + { + auto resp = HttpResponse::newHttpResponse(k400BadRequest, CT_NONE); + resp->setCloseConnection(true); + callback(resp); + return; + } + RouteResult result = HttpControllersRouter::instance().routeWs(req); if (result.result == RouteResult::Success) @@ -1157,6 +1166,15 @@ void HttpServer::sendResponses( buffer.retrieveAll(); } +static bool isValidWebSocketKey(std::string_view key) +{ + if (key.size() != 24 || !drogon::utils::isBase64(key)) + return false; + + const auto decoded = drogon::utils::base64Decode(key); + return decoded.size() == 16 && drogon::utils::base64Encode(decoded) == key; +} + static inline bool isWebSocket(const HttpRequestImplPtr &req) { if (req->method() != Get) diff --git a/lib/src/Utilities.cc b/lib/src/Utilities.cc index f82472850e..59248c21f5 100644 --- a/lib/src/Utilities.cc +++ b/lib/src/Utilities.cc @@ -911,8 +911,9 @@ std::string urlDecode(const char *begin, const char *end) result += ' '; break; case '%': - if ((i + 2) < len && isxdigit(begin[i + 1]) && - isxdigit(begin[i + 2])) + if ((i + 2) < len && + isxdigit(static_cast(begin[i + 1])) && + isxdigit(static_cast(begin[i + 2]))) { unsigned int x1 = begin[i + 1]; if (x1 >= '0' && x1 <= '9') diff --git a/lib/src/WebSocketClientImpl.cc b/lib/src/WebSocketClientImpl.cc index f979668291..c76e39af59 100644 --- a/lib/src/WebSocketClientImpl.cc +++ b/lib/src/WebSocketClientImpl.cc @@ -256,6 +256,9 @@ void WebSocketClientImpl::onRecvMessage( auto acceptStr = resp->getHeaderBy("sec-websocket-accept"); if (resp->statusCode() != k101SwitchingProtocols || + !drogon::utils::ci_equals(resp->getHeaderBy("upgrade"), + "websocket") || + !containsHttpToken(resp->getHeaderBy("connection"), "upgrade") || acceptStr != wsAccept_) { requestCallback_(ReqResult::BadResponse,