Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: Model Django REST framework #7016

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -155,6 +155,7 @@ Python built-in support
Name, Category
aiohttp.web, Web framework
Django, Web framework
djangorestframework, Web framework
FastAPI, Web framework
Flask, Web framework
Tornado, Web framework
@@ -0,0 +1,2 @@
lgtm,codescanning
* Added modeling of HTTP requests and responses when using the Django REST Framework (`djangorestframework` PyPI package), which leads to additional remote flow sources.
@@ -27,6 +27,7 @@ private import semmle.python.frameworks.Peewee
private import semmle.python.frameworks.Psycopg2
private import semmle.python.frameworks.Pydantic
private import semmle.python.frameworks.PyMySQL
private import semmle.python.frameworks.RestFramework
private import semmle.python.frameworks.Rsa
private import semmle.python.frameworks.RuamelYaml
private import semmle.python.frameworks.Simplejson
@@ -17,10 +17,12 @@ private import semmle.python.frameworks.internal.SelfRefMixin
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper

/**
* INTERNAL: Do not use.
*
* Provides models for the `django` PyPI package.
* See https://www.djangoproject.com/.
*/
private module Django {
module Django {
/** Provides models for the `django.views` module */
module Views {
/**
@@ -367,6 +369,52 @@ private module Django {
}
}

/**
* Provides models for the `django.contrib.auth.models.User` class
*
* See https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#user-model.
*/
module User {
/**
* A source of instances of `django.contrib.auth.models.User`, extend this class to model new instances.
*
* This can include instantiations of the class, return values from function
* calls, or a special parameter that will be set when functions are called by an external
* library.
*
* Use the predicate `User::instance()` to get references to instances of `django.contrib.auth.models.User`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }

/** Gets a reference to an instance of `django.contrib.auth.models.User`. */
private DataFlow::TypeTrackingNode instance(DataFlow::TypeTracker t) {
t.start() and
result instanceof InstanceSource
or
exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))
}

/** Gets a reference to an instance of `django.contrib.auth.models.User`. */
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }

/**
* Taint propagation for `django.contrib.auth.models.User`.
*/
private class InstanceTaintSteps extends InstanceTaintStepsHelper {
InstanceTaintSteps() { this = "django.contrib.auth.models.User" }

override DataFlow::Node getInstance() { result = instance() }

override string getAttributeName() {
result in ["username", "first_name", "last_name", "email"]
}

override string getMethodName() { none() }

override string getAsyncMethodName() { none() }
}
}

/**
* Provides models for the `django.core.files.uploadedfile.UploadedFile` class
*
@@ -466,10 +514,12 @@ private module Django {
}

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

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

/** Provides models for the `django.conf` module */
module conf {
/** Provides models for the `django.conf.urls` module */
module conf_urls {
// -------------------------------------------------------------------------
// django.conf.urls
@@ -890,14 +942,15 @@ private module PrivateDjango {
* See https://docs.djangoproject.com/en/3.1/ref/request-response/#django.http.HttpResponse.
*/
module HttpResponse {
/** Gets a reference to the `django.http.response.HttpResponse` class. */
API::Node baseClassRef() {
result = response().getMember("HttpResponse")
or
// Handle `django.http.HttpResponse` alias
result = http().getMember("HttpResponse")
}

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

/**
@@ -1893,14 +1946,11 @@ private module PrivateDjango {
* with the django framework.
*
* Most functions take a django HttpRequest as a parameter (but not all).
*
* Extend this class to refine existing API models. If you want to model new APIs,
* extend `DjangoRouteHandler::Range` instead.
*/
private class DjangoRouteHandler extends Function {
DjangoRouteHandler() {
exists(DjangoRouteSetup route | route.getViewArg() = poorMansFunctionTracker(this))
or
any(DjangoViewClass vc).getARequestHandler() = this
}

class DjangoRouteHandler extends Function instanceof DjangoRouteHandler::Range {
/**
* Gets the index of the parameter where the first routed parameter can be passed --
* that is, the one just after any possible `self` or HttpRequest parameters.
@@ -1920,6 +1970,24 @@ private module PrivateDjango {
Parameter getRequestParam() { result = this.getArg(this.getRequestParamIndex()) }
}

/** Provides a class for modeling new django route handlers. */
module DjangoRouteHandler {
/**
* Extend this class to model new APIs. If you want to refine existing API models,
* extend `DjangoRouteHandler` instead.
*/
abstract class Range extends Function { }

/** Route handlers from normal usage of django. */
private class StandardDjangoRouteHandlers extends Range {
StandardDjangoRouteHandlers() {
exists(DjangoRouteSetup route | route.getViewArg() = poorMansFunctionTracker(this))
or
any(DjangoViewClass vc).getARequestHandler() = this
}
}
}

/**
* A method named `get_redirect_url` on a django view class.
*
@@ -1941,7 +2009,7 @@ private module PrivateDjango {
}

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