Skip to content

Commit 9f614b1

Browse files
authored
Merge pull request #7016 from RasmusWL/django-rest-framework
Python: Model Django REST framework
2 parents 55ea715 + 491f72b commit 9f614b1

File tree

32 files changed

+1257
-12
lines changed

32 files changed

+1257
-12
lines changed

docs/codeql/support/reusables/frameworks.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Python built-in support
164164
Name, Category
165165
aiohttp.web, Web framework
166166
Django, Web framework
167+
djangorestframework, Web framework
167168
FastAPI, Web framework
168169
Flask, Web framework
169170
Tornado, Web framework
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* Added modeling of HTTP requests and responses when using the Django REST Framework (`djangorestframework` PyPI package), which leads to additional remote flow sources.

python/ql/lib/semmle/python/Frameworks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ private import semmle.python.frameworks.Peewee
3030
private import semmle.python.frameworks.Psycopg2
3131
private import semmle.python.frameworks.Pydantic
3232
private import semmle.python.frameworks.PyMySQL
33+
private import semmle.python.frameworks.RestFramework
3334
private import semmle.python.frameworks.Rsa
3435
private import semmle.python.frameworks.RuamelYaml
3536
private import semmle.python.frameworks.Simplejson

python/ql/lib/semmle/python/frameworks/Django.qll

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ private import semmle.python.frameworks.internal.SelfRefMixin
1717
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
1818

1919
/**
20+
* INTERNAL: Do not use.
21+
*
2022
* Provides models for the `django` PyPI package.
2123
* See https://www.djangoproject.com/.
2224
*/
23-
private module Django {
25+
module Django {
2426
/** Provides models for the `django.views` module */
2527
module Views {
2628
/**
@@ -367,6 +369,52 @@ private module Django {
367369
}
368370
}
369371

372+
/**
373+
* Provides models for the `django.contrib.auth.models.User` class
374+
*
375+
* See https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#user-model.
376+
*/
377+
module User {
378+
/**
379+
* A source of instances of `django.contrib.auth.models.User`, extend this class to model new instances.
380+
*
381+
* This can include instantiations of the class, return values from function
382+
* calls, or a special parameter that will be set when functions are called by an external
383+
* library.
384+
*
385+
* Use the predicate `User::instance()` to get references to instances of `django.contrib.auth.models.User`.
386+
*/
387+
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
388+
389+
/** Gets a reference to an instance of `django.contrib.auth.models.User`. */
390+
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
391+
t.start() and
392+
result instanceof InstanceSource
393+
or
394+
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
395+
}
396+
397+
/** Gets a reference to an instance of `django.contrib.auth.models.User`. */
398+
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
399+
400+
/**
401+
* Taint propagation for `django.contrib.auth.models.User`.
402+
*/
403+
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
404+
InstanceTaintSteps() { this = "django.contrib.auth.models.User" }
405+
406+
override DataFlow::Node getInstance() { result = instance() }
407+
408+
override string getAttributeName() {
409+
result in ["username", "first_name", "last_name", "email"]
410+
}
411+
412+
override string getMethodName() { none() }
413+
414+
override string getAsyncMethodName() { none() }
415+
}
416+
}
417+
370418
/**
371419
* Provides models for the `django.core.files.uploadedfile.UploadedFile` class
372420
*
@@ -466,10 +514,12 @@ private module Django {
466514
}
467515

468516
/**
517+
* INTERNAL: Do not use.
518+
*
469519
* Provides models for the `django` PyPI package (that we are not quite ready to publicly expose yet).
470520
* See https://www.djangoproject.com/.
471521
*/
472-
private module PrivateDjango {
522+
module PrivateDjango {
473523
// ---------------------------------------------------------------------------
474524
// django
475525
// ---------------------------------------------------------------------------
@@ -496,6 +546,7 @@ private module PrivateDjango {
496546
/** Gets a reference to the `django.db.connection` object. */
497547
API::Node connection() { result = db().getMember("connection") }
498548

549+
/** A `django.db.connection` is a PEP249 compliant DB connection. */
499550
class DjangoDbConnection extends PEP249::Connection::InstanceSource {
500551
DjangoDbConnection() { this = connection().getAUse() }
501552
}
@@ -692,6 +743,7 @@ private module PrivateDjango {
692743

693744
/** Provides models for the `django.conf` module */
694745
module conf {
746+
/** Provides models for the `django.conf.urls` module */
695747
module conf_urls {
696748
// -------------------------------------------------------------------------
697749
// django.conf.urls
@@ -890,14 +942,15 @@ private module PrivateDjango {
890942
* See https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpResponse.
891943
*/
892944
module HttpResponse {
945+
/** Gets a reference to the `django.http.response.HttpResponse` class. */
893946
API::Node baseClassRef() {
894947
result = response().getMember("HttpResponse")
895948
or
896949
// Handle `django.http.HttpResponse` alias
897950
result = http().getMember("HttpResponse")
898951
}
899952

900-
/** Gets a reference to the `django.http.response.HttpResponse` class. */
953+
/** Gets a reference to the `django.http.response.HttpResponse` class or any subclass. */
901954
API::Node classRef() { result = baseClassRef().getASubclass*() }
902955

903956
/**
@@ -1893,14 +1946,11 @@ private module PrivateDjango {
18931946
* with the django framework.
18941947
*
18951948
* Most functions take a django HttpRequest as a parameter (but not all).
1949+
*
1950+
* Extend this class to refine existing API models. If you want to model new APIs,
1951+
* extend `DjangoRouteHandler::Range` instead.
18961952
*/
1897-
private class DjangoRouteHandler extends Function {
1898-
DjangoRouteHandler() {
1899-
exists(DjangoRouteSetup route | route.getViewArg() = poorMansFunctionTracker(this))
1900-
or
1901-
any(DjangoViewClass vc).getARequestHandler() = this
1902-
}
1903-
1953+
class DjangoRouteHandler extends Function instanceof DjangoRouteHandler::Range {
19041954
/**
19051955
* Gets the index of the parameter where the first routed parameter can be passed --
19061956
* that is, the one just after any possible `self` or HttpRequest parameters.
@@ -1920,6 +1970,24 @@ private module PrivateDjango {
19201970
Parameter getRequestParam() { result = this.getArg(this.getRequestParamIndex()) }
19211971
}
19221972

1973+
/** Provides a class for modeling new django route handlers. */
1974+
module DjangoRouteHandler {
1975+
/**
1976+
* Extend this class to model new APIs. If you want to refine existing API models,
1977+
* extend `DjangoRouteHandler` instead.
1978+
*/
1979+
abstract class Range extends Function { }
1980+
1981+
/** Route handlers from normal usage of django. */
1982+
private class StandardDjangoRouteHandlers extends Range {
1983+
StandardDjangoRouteHandlers() {
1984+
exists(DjangoRouteSetup route | route.getViewArg() = poorMansFunctionTracker(this))
1985+
or
1986+
any(DjangoViewClass vc).getARequestHandler() = this
1987+
}
1988+
}
1989+
}
1990+
19231991
/**
19241992
* A method named `get_redirect_url` on a django view class.
19251993
*
@@ -1941,7 +2009,7 @@ private module PrivateDjango {
19412009
}
19422010

19432011
/** A data-flow node that sets up a route on a server, using the django framework. */
1944-
abstract private class DjangoRouteSetup extends HTTP::Server::RouteSetup::Range, DataFlow::CfgNode {
2012+
abstract class DjangoRouteSetup extends HTTP::Server::RouteSetup::Range, DataFlow::CfgNode {
19452013
/** Gets the data-flow node that is used as the argument for the view handler. */
19462014
abstract DataFlow::Node getViewArg();
19472015

0 commit comments

Comments
 (0)