forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathManuallyCheckHttpVerb.ql
More file actions
102 lines (87 loc) · 3.53 KB
/
ManuallyCheckHttpVerb.ql
File metadata and controls
102 lines (87 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* @name Manually checking http verb instead of using built in rails routes and protections
* @description Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods.
* @kind path-problem
* @problem.severity error
* @security-severity 5.0
* @precision low
* @id rb/manually-checking-http-verb
* @tags security
* experimental
*/
import codeql.ruby.AST
import codeql.ruby.DataFlow
import codeql.ruby.controlflow.CfgNodes
import codeql.ruby.frameworks.ActionController
import codeql.ruby.TaintTracking
// any `request` calls in an action method
class Request extends DataFlow::CallNode {
Request() {
this.getMethodName() = "request" and
this.asExpr().getExpr().getEnclosingMethod() instanceof ActionControllerActionMethod
}
}
// `request.env`
class RequestEnvMethod extends DataFlow::CallNode {
RequestEnvMethod() {
this.getMethodName() = "env" and
any(Request r).flowsTo(this.getReceiver())
}
}
// `request.request_method`
class RequestRequestMethod extends DataFlow::CallNode {
RequestRequestMethod() {
this.getMethodName() = "request_method" and
any(Request r).flowsTo(this.getReceiver())
}
}
// `request.method`
class RequestMethod extends DataFlow::CallNode {
RequestMethod() {
this.getMethodName() = "method" and
any(Request r).flowsTo(this.getReceiver())
}
}
// `request.raw_request_method`
class RequestRawRequestMethod extends DataFlow::CallNode {
RequestRawRequestMethod() {
this.getMethodName() = "raw_request_method" and
any(Request r).flowsTo(this.getReceiver())
}
}
// `request.request_method_symbol`
class RequestRequestMethodSymbol extends DataFlow::CallNode {
RequestRequestMethodSymbol() {
this.getMethodName() = "request_method_symbol" and
any(Request r).flowsTo(this.getReceiver())
}
}
// `request.get?`
class RequestGet extends DataFlow::CallNode {
RequestGet() {
this.getMethodName() = "get?" and
any(Request r).flowsTo(this.getReceiver())
}
}
private module HttpVerbConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RequestMethod or
source instanceof RequestRequestMethod or
source instanceof RequestEnvMethod or
source instanceof RequestRawRequestMethod or
source instanceof RequestRequestMethodSymbol or
source instanceof RequestGet
}
predicate isSink(DataFlow::Node sink) {
exists(ExprNodes::ConditionalExprCfgNode c | c.getCondition() = sink.asExpr()) or
exists(ExprNodes::CaseExprCfgNode c | c.getValue() = sink.asExpr())
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
}
private module HttpVerbFlow = TaintTracking::Global<HttpVerbConfig>;
import HttpVerbFlow::PathGraph
from HttpVerbFlow::PathNode source, HttpVerbFlow::PathNode sink
where HttpVerbFlow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Manually checking HTTP verbs is an indication that multiple requests are routed to the same controller action. This could lead to bypassing necessary authorization methods and other protections, like CSRF protection. Prefer using different controller actions for each HTTP method and relying Rails routing to handle mapping resources and verbs to specific methods."