diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 1d8de8ea471..b6d367bc32c 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -15,6 +15,7 @@ import semmle.code.java.frameworks.ApacheHttp import semmle.code.java.frameworks.android.XmlParsing import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.JaxWS +import semmle.code.java.frameworks.javase.WebSocket import semmle.code.java.frameworks.android.Intent import semmle.code.java.frameworks.spring.SpringWeb import semmle.code.java.frameworks.spring.SpringController @@ -155,6 +156,14 @@ private class ThriftIfaceParameterSource extends RemoteFlowSource { override string getSourceType() { result = "Thrift Iface parameter" } } +private class WebSocketMessageParameterSource extends RemoteFlowSource { + WebSocketMessageParameterSource() { + exists(WebsocketOnText t | t.getParameter(1) = this.asParameter()) + } + + override string getSourceType() { result = "Websocket onText parameter" } +} + /** Class for `tainted` user input. */ abstract class UserInput extends DataFlow::Node { } diff --git a/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll b/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll new file mode 100644 index 00000000000..17d3d4579d2 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll @@ -0,0 +1,21 @@ +/** + * Provides classes for identifying methods called by the Java SE WebSocket package. + */ + +import java + +/** The `java.net.http.Websocket.Listener` interface. */ +class WebsocketListener extends Interface { + WebsocketListener() { this.hasQualifiedName("java.net.http", "WebSocket$Listener") } +} + +/** The method `onText` on a type that implements the `java.net.http.Websocket.Listener` interface. */ +class WebsocketOnText extends Method { + WebsocketOnText() { + exists(WebsocketListener l | + this.getDeclaringType().extendsOrImplements(l) and + // onText(WebSocket webSocket, CharSequence data, boolean last) + this.hasName("onText") + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java new file mode 100644 index 00000000000..6d069c6f118 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java @@ -0,0 +1,27 @@ +// package test.cwe079.cwe.examples; + +// import java.net.http.HttpClient; +// import java.net.http.WebSocket; +// import java.net.URI; +// import java.util.*; +// import java.util.concurrent.*; + +// public class WebsocketXss { +// public static void main(String[] args) throws Exception { +// WebSocket.Listener listener = new WebSocket.Listener() { +// public CompletionStage onText(WebSocket webSocket, CharSequence message, boolean last) { +// try { +// HttpClient client = HttpClient.newBuilder().build(); +// CompletableFuture ws = client.newWebSocketBuilder() +// .buildAsync(URI.create("ws://websocket.example.com"), null); +// ws.get().sendText(message, false); +// } catch (Exception e) { +// // TODO: handle exception +// } + +// return null; +// }; +// }; + +// } +// }