mirror of
https://github.com/github/codeql.git
synced 2026-04-21 06:55:31 +02:00
Java: Calling openStream on URLs created from remote source can lead to local file disclosure.
This commit is contained in:
8
java/ql/src/Security/CWE/CWE-036/OpenStream.java
Normal file
8
java/ql/src/Security/CWE/CWE-036/OpenStream.java
Normal file
@@ -0,0 +1,8 @@
|
||||
public class TestServlet extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
// BAD: a URL from a remote source is opened with URL#openStream()
|
||||
URL url = new URL(request.getParameter("url"));
|
||||
InputStream inputStream = new URL(url).openStream();
|
||||
}
|
||||
}
|
||||
39
java/ql/src/Security/CWE/CWE-036/OpenStream.qhelp
Normal file
39
java/ql/src/Security/CWE/CWE-036/OpenStream.qhelp
Normal file
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Calling <code>openStream</code> on URLs created from remote source can lead to local file disclosure.</p>
|
||||
|
||||
<p>If <code>openStream</code> is called on a <code>java.net.URL</code>, that was created from a remote source
|
||||
an attacker can try to pass absolute URLs starting with <code>file://</code> or <code>jar://</code> to access
|
||||
local resources in addition to remote ones.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>When you construct a URL using <code>java.net.URL</code> from a remote source, make sure
|
||||
to not call openStream on it. Instead fetch the URL with a HTTP Client to access its content.
|
||||
Also validate that the URL uses the correct protocol and host combination.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following example shows an URL that is constructed from a request parameter. Afterwards <code>openStream</code>
|
||||
is called on the URL, potentially leading to a local file access.</p>
|
||||
|
||||
<sample src="OpenStream.java" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>Java Platform, Standard Edition 11, API Specification:
|
||||
<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/URL.html">
|
||||
Class URL</a>.</li>
|
||||
<li>
|
||||
|
||||
<!-- LocalWords: CWE
|
||||
-->
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
50
java/ql/src/Security/CWE/CWE-036/OpenStream.ql
Normal file
50
java/ql/src/Security/CWE/CWE-036/OpenStream.ql
Normal file
@@ -0,0 +1,50 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class URLConstructor extends ClassInstanceExpr {
|
||||
URLConstructor() { this.getConstructor().getDeclaringType().getQualifiedName() = "java.net.URL" }
|
||||
|
||||
Expr stringArg() {
|
||||
// Query only in URL's that were constructed by calling the single parameter string constructor.
|
||||
if
|
||||
this.getConstructor().getNumberOfParameters() = 1 and
|
||||
this.getConstructor().getParameter(0).getType().getName() = "String"
|
||||
then result = this.getArgument(0)
|
||||
else none()
|
||||
}
|
||||
}
|
||||
|
||||
class URLOpenStreamMethod extends Method {
|
||||
URLOpenStreamMethod() {
|
||||
this.getDeclaringType().getQualifiedName() = "java.net.URL" and
|
||||
this.getName() = "openStream"
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteURLToOpenStreamFlowConfig extends TaintTracking::Configuration {
|
||||
RemoteURLToOpenStreamFlowConfig() { this = "OpenStream::RemoteURLToOpenStreamFlowConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess m |
|
||||
sink.asExpr() = m.getQualifier() and m.getMethod() instanceof URLOpenStreamMethod
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(URLConstructor u |
|
||||
node1.asExpr() = u.stringArg() and
|
||||
node2.asExpr() = u
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, MethodAccess call
|
||||
where
|
||||
sink.getNode().asExpr() = call.getQualifier() and
|
||||
any(RemoteURLToOpenStreamFlowConfig c).hasFlowPath(source, sink)
|
||||
select call, source, sink,
|
||||
"URL on which openStream is called may have been constructed from remote source"
|
||||
Reference in New Issue
Block a user