Python: Implement routed parameter for django.urls.path

Matching current implementation in
f07a7bf8cf/python/ql/src/semmle/python/web/django/General.qll (L125-L133)
This commit is contained in:
Rasmus Wriedt Larsen
2020-10-15 20:12:02 +02:00
parent 8803fb2778
commit ff8708df67
3 changed files with 50 additions and 13 deletions

View File

@@ -160,6 +160,34 @@ private module Django {
result = djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker::end(), func)
}
/**
* A function that is used as a django route handler.
*/
private class DjangoRouteHandler extends Function {
DjangoRouteHandler() { exists(djangoRouteHandlerFunctionTracker(this)) }
/** Gets the index of the request parameter. */
int getRequestParamIndex() {
not this.isMethod() and
result = 0
or
this.isMethod() and
result = 1
}
/** Gets the request parameter. */
Parameter getRequestParam() { result = this.getArg(this.getRequestParamIndex()) }
}
/**
* Gets the regex that is used by django to find routed parameters when using `django.urls.path`.
*
* Taken from https://github.com/django/django/blob/7d1bf29977bb368d7c28e7c6eb146db3b3009ae7/django/urls/resolvers.py#L199
*/
private string pathRoutedParameterRegex() {
result = "<(?:(?<converter>[^>:]+):)?(?<parameter>\\w+)>"
}
/**
* A call to `django.urls.path`.
*
@@ -174,14 +202,31 @@ private module Django {
result.asCfgNode() = [node.getArg(0), node.getArgByName("route")]
}
override Function getARouteHandler() {
override DjangoRouteHandler getARouteHandler() {
exists(DataFlow::Node viewArg |
viewArg.asCfgNode() in [node.getArg(1), node.getArgByName("view")] and
djangoRouteHandlerFunctionTracker(result) = viewArg
)
}
override Parameter getARoutedParameter() { none() }
override Parameter getARoutedParameter() {
// If we don't know the URL pattern, we simply mark all parameters as a routed
// parameter. This should give us more RemoteFlowSources but could also lead to
// more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
exists(DjangoRouteHandler routeHandler | routeHandler = this.getARouteHandler() |
not exists(this.getUrlPattern()) and
result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and
not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i))
)
or
exists(string name |
result = this.getARouteHandler().getArgByName(name) and
exists(string match |
match = this.getUrlPattern().regexpFind(pathRoutedParameterRegex(), _, _) and
name = match.regexpCapture(pathRoutedParameterRegex(), 2)
)
)
}
}
/**
@@ -198,7 +243,7 @@ private module Django {
result.asCfgNode() = [node.getArg(0), node.getArgByName("route")]
}
override Function getARouteHandler() {
override DjangoRouteHandler getARouteHandler() {
exists(DataFlow::Node viewArg |
viewArg.asCfgNode() in [node.getArg(1), node.getArgByName("view")] and
djangoRouteHandlerFunctionTracker(result) = viewArg

View File

@@ -3,13 +3,5 @@
| routing_test.py:39:45:39:88 | Comment # $routeHandler $routedParameter=page_number | Missing result:routedParameter=page_number |
| routing_test.py:44:62:44:120 | Comment # $routeHandler $routedParameter=arg0 $routedParameter=arg1 | Missing result:routedParameter=arg0 |
| routing_test.py:44:62:44:120 | Comment # $routeHandler $routedParameter=arg0 $routedParameter=arg1 | Missing result:routedParameter=arg1 |
| routing_test.py:78:43:78:86 | Comment # $routeHandler $routedParameter=page_number | Missing result:routedParameter=page_number |
| routing_test.py:81:43:81:120 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar $routedParameter=baz | Missing result:routedParameter=bar |
| routing_test.py:81:43:81:120 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar $routedParameter=baz | Missing result:routedParameter=baz |
| routing_test.py:81:43:81:120 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar $routedParameter=baz | Missing result:routedParameter=foo |
| routing_test.py:84:38:84:94 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar | Missing result:routedParameter=bar |
| routing_test.py:84:38:84:94 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar | Missing result:routedParameter=foo |
| taint_test.py:6:60:6:116 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar | Missing result:routedParameter=bar |
| taint_test.py:6:60:6:116 | Comment # $routeHandler $routedParameter=foo $routedParameter=bar | Missing result:routedParameter=foo |
| testapp/views.py:3:33:3:47 | Comment # $routeHandler | Missing result:routeHandler= |
| testapp/views.py:6:37:6:51 | Comment # $routeHandler | Missing result:routeHandler= |

View File

@@ -1,5 +1,5 @@
| taint_test.py:7 | fail | test_taint | bar |
| taint_test.py:7 | fail | test_taint | foo |
| taint_test.py:7 | ok | test_taint | bar |
| taint_test.py:7 | ok | test_taint | foo |
| taint_test.py:8 | ok | test_taint | baz |
| taint_test.py:14 | fail | test_taint | request |
| taint_test.py:16 | fail | test_taint | request.body |