mirror of
https://github.com/github/codeql.git
synced 2026-04-21 06:55:31 +02:00
Ruby: Make csrf query more specific
CSRF protection only needs to be explicitly enabled on Rails applications < 5.2 _or_ those that don't include a `load_defaults` call with a version >= 5.2.
This commit is contained in:
@@ -15,6 +15,7 @@ import codeql.ruby.AST
|
||||
import codeql.ruby.Concepts
|
||||
import codeql.ruby.frameworks.ActionController
|
||||
import codeql.ruby.frameworks.Gemfile
|
||||
import codeql.ruby.DataFlow
|
||||
|
||||
/**
|
||||
* Holds if a call to `protect_from_forgery` is made in the controller class `definedIn`,
|
||||
@@ -28,23 +29,39 @@ private predicate protectFromForgeryCall(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the Gemfile for this application specifies a version of "rails" < 3.0.0.
|
||||
* Rails versions from 3.0.0 onwards enable CSRF protection by default.
|
||||
* Holds if the Gemfile for this application specifies a version of "rails" or "actionpack" < 5.2.
|
||||
* Rails versions prior to 5.2 do not enable CSRF protection by default.
|
||||
*/
|
||||
private predicate railsPreVersion3() {
|
||||
exists(Gemfile::Gem g | g.getName() = "rails" and g.getAVersionConstraint().before("5.2"))
|
||||
private predicate railsPreVersion5_2() {
|
||||
exists(Gemfile::Gem g |
|
||||
g.getName() = ["rails", "actionpack"] and g.getAVersionConstraint().before("5.2")
|
||||
)
|
||||
}
|
||||
|
||||
private float getRailsConfigDefaultVersion() {
|
||||
exists(DataFlow::CallNode config, DataFlow::CallNode loadDefaultsCall |
|
||||
DataFlow::getConstant("Rails")
|
||||
.getConstant("Application")
|
||||
.getADescendentModule()
|
||||
.getAnImmediateReference()
|
||||
.flowsTo(config.getReceiver()) and
|
||||
config.getMethodName() = "config" and
|
||||
loadDefaultsCall.getReceiver() = config and
|
||||
loadDefaultsCall.getMethodName() = "load_defaults" and
|
||||
result = loadDefaultsCall.getArgument(0).getConstantValue().getFloat()
|
||||
)
|
||||
}
|
||||
|
||||
from ActionControllerClass c
|
||||
where
|
||||
not protectFromForgeryCall(_, c, _) and
|
||||
// Rails versions prior to 3.0.0 require CSRF protection to be explicitly enabled.
|
||||
// For later versions, there must exist a call to `csrf_meta_tags` in every HTML response.
|
||||
// We currently just check for a call to this method anywhere in the codebase.
|
||||
(
|
||||
railsPreVersion3()
|
||||
// Rails versions prior to 5.2 require CSRF protection to be explicitly enabled.
|
||||
railsPreVersion5_2()
|
||||
or
|
||||
not any(MethodCall m).getMethodName() = ["csrf_meta_tags", "csrf_meta_tag"]
|
||||
// For Rails >= 5.2, CSRF protection is enabled by default if there is a `load_defaults` call in the root application class
|
||||
// which specifies a version >= 5.2.
|
||||
not getRailsConfigDefaultVersion() >= 5.2
|
||||
) and
|
||||
// Only generate alerts for the topmost controller in the tree.
|
||||
not exists(ActionControllerClass parent | c = parent.getAnImmediateDescendent())
|
||||
|
||||
Reference in New Issue
Block a user