Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d3232c

Browse files
authored
refactor to use data flow
1 parent 96e66c4 commit 5d3232c

2 files changed

Lines changed: 23 additions & 58 deletions

File tree

ruby/ql/src/experimental/weak-params/WeakParams.ql

Lines changed: 22 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -11,97 +11,62 @@
1111
*/
1212

1313
import ruby
14+
import codeql.ruby.Concepts
1415
import codeql.ruby.DataFlow
1516
import codeql.ruby.TaintTracking
17+
import codeql.ruby.frameworks.ActionController
1618
import DataFlow::PathGraph
1719

1820
/**
19-
* A direct parameters reference that happens outside of a strong params method but inside
20-
* of a controller class
21+
* A call to `request` in an ActionController controller class.
22+
* This probably refers to the incoming HTTP request object.
2123
*/
22-
class WeakParams extends Expr {
23-
WeakParams() {
24-
(
25-
allParamsAccess(this) or
26-
this instanceof ParamsReference
27-
) and
28-
this.getEnclosingModule() instanceof ControllerClass and
29-
not this.getEnclosingMethod() instanceof StrongParamsMethod
24+
class ActionControllerRequest extends DataFlow::Node {
25+
ActionControllerRequest() {
26+
exists(DataFlow::CallNode c |
27+
c.asExpr().getExpr().getEnclosingModule() instanceof ActionControllerControllerClass and
28+
c.getMethodName() = "request"
29+
|
30+
c.flowsTo(this)
31+
)
3032
}
3133
}
3234

3335
/**
34-
* A controller class, which extendsd `ApplicationController`
35-
*/
36-
class ControllerClass extends ModuleBase {
37-
ControllerClass() { this.getModule().getSuperClass+().toString() = "ApplicationController" }
38-
}
39-
40-
/**
41-
* A method that follows the strong params naming convention
36+
* A direct parameters reference that happens inside a controller class.
4237
*/
43-
class StrongParamsMethod extends Method {
44-
StrongParamsMethod() { this.getName().regexpMatch(".*_params") }
38+
class WeakParams extends DataFlow::CallNode {
39+
WeakParams() {
40+
this.getReceiver() instanceof ActionControllerRequest and
41+
allParamsAccess(this.asExpr().getExpr())
42+
}
4543
}
4644

4745
/**
4846
* Holds call to a method that exposes or accesses all parameters from an inbound HTTP request
4947
*/
5048
predicate allParamsAccess(MethodCall call) {
51-
call.getMethodName() = "expose_all" or
52-
call.getMethodName() = "original_hash" or
5349
call.getMethodName() = "path_parametes" or
5450
call.getMethodName() = "query_parameters" or
5551
call.getMethodName() = "request_parameters" or
5652
call.getMethodName() = "GET" or
5753
call.getMethodName() = "POST"
5854
}
5955

60-
/**
61-
* A reference to an element in the `params` object
62-
*/
63-
class ParamsReference extends ElementReference {
64-
ParamsReference() { this.getAChild().toString() = "params" }
65-
}
66-
67-
/**
68-
* A Model or ViewModel classes with a base class of `ViewModel`, `ApplicationRecord` or includes `ActionModel::Model`,
69-
* which are required to support the strong parameters pattern
70-
*/
71-
class ModelClass extends ModuleBase {
72-
ModelClass() {
73-
this.getModule().getSuperClass+().toString() = "ViewModel" or
74-
this.getModule().getSuperClass+().toString() = "ApplicationRecord" or
75-
this.getModule().getSuperClass+().getAnIncludedModule().toString() = "ActionModel::Model"
76-
}
77-
}
78-
79-
/**
80-
* A DataFlow::Node representation that corresponds to any argument passed into a method call
81-
* where the receiver is an instance of ModelClass
82-
*/
83-
class ModelClassMethodArgument extends DataFlow::Node {
84-
85-
ModelClassMethodArgument() {
86-
exists( DataFlow::CallNode call | this = call.getArgument(_) |
87-
call.getExprNode().getNode().getParent+() instanceof ModelClass )
88-
}
89-
}
90-
9156
/**
9257
* A Taint tracking config where the source is a weak params access in a controller and the sink
9358
* is a method call of a model class
9459
*/
9560
class Configuration extends TaintTracking::Configuration {
96-
Configuration() { this = "Configuration" }
61+
Configuration() { this = "WeakParamsConfiguration" }
9762

98-
override predicate isSource(DataFlow::Node node) { node.asExpr().getNode() instanceof WeakParams }
63+
override predicate isSource(DataFlow::Node node) { node instanceof WeakParams }
9964

10065
// the sink is an instance of a Model class that receives a method call
101-
override predicate isSink(DataFlow::Node node) { node instanceof ModelClassMethodArgument }
66+
override predicate isSink(DataFlow::Node node) { node = any(PersistentWriteAccess a).getValue() }
10267
}
10368

10469
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
10570
where config.hasFlowPath(source, sink)
106-
select sink.getNode().(ModelClassMethodArgument), source, sink,
71+
select sink.getNode(), source, sink,
10772
"By exposing all keys in request parameters or by blindy accessing them, unintended parameters could be used and lead to mass-assignment or have other unexpected side-effects. It is safer to follow the 'strong parameters' pattern in Rails, which is outlined here: https://api.rubyonrails.org/classes/ActionController/StrongParameters.html"

ruby/ql/test/query-tests/experimental/weak-params/WeakParams.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def create_query
88
end
99

1010
def update
11-
TestObect.update(object_params)
11+
TestObject.update(object_params)
1212
end
1313

1414
#

0 commit comments

Comments
 (0)