Skip to content

Commit 9b969e1

Browse files
committed
Modify according to @yoff suggestion
1 parent 0277601 commit 9b969e1

File tree

2 files changed

+46
-43
lines changed

2 files changed

+46
-43
lines changed

python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheck.ql

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ class ClientSuppliedIpUsedInSecurityCheckConfig extends TaintTracking::Configura
2727
source instanceof ClientSuppliedIpUsedInSecurityCheck
2828
}
2929

30-
override predicate isSink(DataFlow::Node sink) {
31-
sink instanceof ClientSuppliedIpUsedInSecurityCheckSink
32-
}
30+
override predicate isSink(DataFlow::Node sink) { sink instanceof PossibleSecurityCheck }
3331

3432
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
3533
exists(DataFlow::CallCfgNode ccn |

python/ql/src/experimental/Security/CWE-348/ClientSuppliedIpUsedInSecurityCheckLib.qll

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -14,55 +14,60 @@ abstract class ClientSuppliedIpUsedInSecurityCheck extends DataFlow::CallCfgNode
1414

1515
private class FlaskClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck {
1616
FlaskClientSuppliedIpUsedInSecurityCheck() {
17-
this =
18-
API::moduleImport("flask")
19-
.getMember("request")
20-
.getMember("headers")
21-
.getMember(["get", "get_all", "getlist"])
22-
.getACall() and
23-
this.getArg(0).asCfgNode().getNode().(StrConst).getText().toLowerCase() =
24-
clientIpParameterName()
17+
exists(RemoteFlowSource rfs, DataFlow::AttrRead get |
18+
rfs.getSourceType() = "flask.request" and this.getFunction() = get
19+
|
20+
// `get` is a call to request.headers.get or request.headers.get_all or request.headers.getlist
21+
// request.headers
22+
get.getObject()
23+
.(DataFlow::AttrRead)
24+
// request
25+
.getObject()
26+
.getALocalSource() = rfs and
27+
get.getAttributeName() in ["get", "get_all", "getlist"] and
28+
get.getObject().(DataFlow::AttrRead).getAttributeName() = "headers" and
29+
this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName()
30+
)
2531
}
2632
}
2733

2834
private class DjangoClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck {
2935
DjangoClientSuppliedIpUsedInSecurityCheck() {
30-
exists(RemoteFlowSource rfs, DataFlow::LocalSourceNode lsn |
31-
rfs.getSourceType() = "django.http.request.HttpRequest" and rfs.asCfgNode() = lsn.asCfgNode()
36+
exists(RemoteFlowSource rfs, DataFlow::AttrRead get |
37+
rfs.getSourceType() = "django.http.request.HttpRequest" and this.getFunction() = get
3238
|
33-
lsn.flowsTo(DataFlow::exprNode(this.getFunction()
34-
.asExpr()
35-
.(Attribute)
36-
.getObject()
37-
.(Attribute)
38-
.getObject())) and
39-
this.getFunction().asExpr().(Attribute).getName() = "get" and
40-
this.getFunction().asExpr().(Attribute).getObject().(Attribute).getName() in [
41-
"headers", "META"
42-
] and
43-
this.getArg(0).asCfgNode().getNode().(StrConst).getText().toLowerCase() =
44-
clientIpParameterName()
39+
// `get` is a call to request.headers.get or request.META.get
40+
// request.headers
41+
get.getObject()
42+
.(DataFlow::AttrRead)
43+
// request
44+
.getObject()
45+
.getALocalSource() = rfs and
46+
get.getAttributeName() = "get" and
47+
get.getObject().(DataFlow::AttrRead).getAttributeName() in ["headers", "META"] and
48+
this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName()
4549
)
4650
}
4751
}
4852

4953
private class TornadoClientSuppliedIpUsedInSecurityCheck extends ClientSuppliedIpUsedInSecurityCheck {
5054
TornadoClientSuppliedIpUsedInSecurityCheck() {
51-
exists(RemoteFlowSource rfs, DataFlow::LocalSourceNode lsn |
52-
rfs.getSourceType() = "tornado.web.RequestHandler" and rfs.asCfgNode() = lsn.asCfgNode()
55+
exists(RemoteFlowSource rfs, DataFlow::AttrRead get |
56+
rfs.getSourceType() = "tornado.web.RequestHandler" and this.getFunction() = get
5357
|
54-
lsn.flowsTo(DataFlow::exprNode(this.getFunction()
55-
.asExpr()
56-
.(Attribute)
57-
.getObject()
58-
.(Attribute)
59-
.getObject()
60-
.(Attribute)
61-
.getObject())) and
62-
this.getFunction().asExpr().(Attribute).getName() in ["get", "get_list"] and
63-
this.getFunction().asExpr().(Attribute).getObject().(Attribute).getName() = "headers" and
64-
this.getArg(0).asCfgNode().getNode().(StrConst).getText().toLowerCase() =
65-
clientIpParameterName()
58+
// `get` is a call to `rfs`.request.headers.get
59+
// `rfs`.request.headers
60+
get.getObject()
61+
.(DataFlow::AttrRead)
62+
// `rfs`.request
63+
.getObject()
64+
.(DataFlow::AttrRead)
65+
// `rfs`
66+
.getObject()
67+
.getALocalSource() = rfs and
68+
get.getAttributeName() in ["get", "get_list"] and
69+
get.getObject().(DataFlow::AttrRead).getAttributeName() = "headers" and
70+
this.getArg(0).asExpr().(StrConst).getText().toLowerCase() = clientIpParameterName()
6671
)
6772
}
6873
}
@@ -77,11 +82,11 @@ private string clientIpParameterName() {
7782
}
7883

7984
/** A data flow sink for ip address forgery vulnerabilities. */
80-
abstract class ClientSuppliedIpUsedInSecurityCheckSink extends DataFlow::Node { }
85+
abstract class PossibleSecurityCheck extends DataFlow::Node { }
8186

8287
/** A data flow sink for sql operation. */
83-
private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink {
84-
SqlOperationSink() { this = any(SqlExecution e).getSql() }
88+
private class SqlOperationAsSecurityCheck extends PossibleSecurityCheck {
89+
SqlOperationAsSecurityCheck() { this = any(SqlExecution e).getSql() }
8590
}
8691

8792
/**
@@ -90,7 +95,7 @@ private class SqlOperationSink extends ClientSuppliedIpUsedInSecurityCheckSink {
9095
* For example: `if not ipAddr.startswith('192.168.') : ...` determine whether the client ip starts
9196
* with `192.168.`, and the program can be deceived by forging the ip address.
9297
*/
93-
private class CompareSink extends ClientSuppliedIpUsedInSecurityCheckSink {
98+
private class CompareSink extends PossibleSecurityCheck {
9499
CompareSink() {
95100
exists(Call call |
96101
call.getFunc().(Attribute).getName() = "startswith" and

0 commit comments

Comments
 (0)