Issue #3462 - fix server validation of websocket upgrade response

Signed-off-by: lachan-roberts <lachlan@webtide.com>
This commit is contained in:
lachan-roberts 2019-03-18 15:12:23 +11:00
parent 53a4a747db
commit 1a20c8cda3
1 changed files with 34 additions and 14 deletions

View File

@ -43,6 +43,7 @@ import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.Behavior; import org.eclipse.jetty.websocket.core.Behavior;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.WebSocketConstants; import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.core.internal.Negotiated; import org.eclipse.jetty.websocket.core.internal.Negotiated;
@ -60,9 +61,8 @@ public final class RFC6455Handshaker implements Handshaker
private static final HttpField CONNECTION_UPGRADE = new PreEncodedHttpField(HttpHeader.CONNECTION, HttpHeader.UPGRADE.asString()); private static final HttpField CONNECTION_UPGRADE = new PreEncodedHttpField(HttpHeader.CONNECTION, HttpHeader.UPGRADE.asString());
private static final HttpField SERVER_VERSION = new PreEncodedHttpField(HttpHeader.SERVER, HttpConfiguration.SERVER_VERSION); private static final HttpField SERVER_VERSION = new PreEncodedHttpField(HttpHeader.SERVER, HttpConfiguration.SERVER_VERSION);
public boolean upgradeRequest(WebSocketNegotiator negotiator, HttpServletRequest request, public boolean upgradeRequest(WebSocketNegotiator negotiator, HttpServletRequest request, HttpServletResponse response,
HttpServletResponse response, FrameHandler.Customizer defaultCustomizer) throws IOException
FrameHandler.Customizer defaultCustomizer) throws IOException
{ {
Request baseRequest = Request.getBaseRequest(request); Request baseRequest = Request.getBaseRequest(request);
HttpChannel httpChannel = baseRequest.getHttpChannel(); HttpChannel httpChannel = baseRequest.getHttpChannel();
@ -153,22 +153,42 @@ public final class RFC6455Handshaker implements Handshaker
return false; return false;
} }
// Check if subprotocol negotiated // validate negotiated subprotocol
String subprotocol = negotiation.getSubprotocol(); String subprotocol = negotiation.getSubprotocol();
if (negotiation.getOfferedSubprotocols().size() > 0) if (subprotocol != null)
{ {
if (subprotocol == null)
{
// TODO: this message needs to be returned to Http Client
LOG.warn("not upgraded: no subprotocol selected from offered subprotocols {}: {}", negotiation.getOfferedSubprotocols(), baseRequest);
return false;
}
if (!negotiation.getOfferedSubprotocols().contains(subprotocol)) if (!negotiation.getOfferedSubprotocols().contains(subprotocol))
{ {
// TODO: this message needs to be returned to Http Client // TODO: this message needs to be returned to Http Client
LOG.warn("not upgraded: selected subprotocol {} not present in offered subprotocols {}: {}", subprotocol, negotiation.getOfferedSubprotocols(), LOG.warn("not upgraded: selected subprotocol {} not present in offered subprotocols {}: {}",
baseRequest); subprotocol, negotiation.getOfferedSubprotocols(), baseRequest);
return false;
}
}
else
{
if (!negotiation.getOfferedSubprotocols().isEmpty())
{
// TODO: this message needs to be returned to Http Client
LOG.warn("not upgraded: no subprotocol selected from offered subprotocols {}: {}",
negotiation.getOfferedSubprotocols(), baseRequest);
return false;
}
}
// validate negotiated extensions
negotiation.getOfferedExtensions();
for (ExtensionConfig config : negotiation.getNegotiatedExtensions())
{
long numMatch = negotiation.getOfferedExtensions().stream().filter(c -> config.getName().equalsIgnoreCase(c.getName())).count();
if (numMatch < 1)
{
LOG.warn("Upgrade failed: negotiated extension not requested {}: {}", config.getName(), baseRequest);
return false;
}
if (numMatch > 1)
{
LOG.warn("Upgrade failed: multiple negotiated extensions of the same name {}: {}", config.getName(), baseRequest);
return false; return false;
} }
} }