Repository navigation
feat: let the text attributes and URL parameters of a request object carry no NOSQL - #163
Merged
Merged
Conversation
…carry no NOSQL A RequestObject model names the inputs that are request objects: the URL parameters a view receives after the request are text, and so is an attribute of the request its model lists, read directly or below a request source such as self.request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Since #158, text input carries no
NOSQL. Flask describes its request attribute by attribute. Django, REST framework, aiohttp and tornado'sself.requesttaint the request object as a whole, sorequest.GET["name"]and every URL parameter carriedNOSQL, like the body. ARequestObject(symbol, text=())model now names the inputs that are request objects:self), then URL parameters, which are text;textattributes gives text, whether read directly (request.GET) or below a request source (self.request.GET);dataand aiohttp'sjson()keep the request's kinds.An attribute read counts only when every source of the value is a request object. Only
NOSQLis affected: text keeps the other kinds.Closes #162.
Declared request objects
HttpRequest/WSGIRequest/ASGIRequest/ DRFRequest, class-based view bases, theirself.request, view decorators, URL registrarsGET,POST,COOKIES,META,headers,path,path_info,method,get_full_path,get_host,query_params, …web.Request,RouteTableDefdecorators, router andweb.*registrationsquery,match_info,headers,cookies,path,url,rel_url,post, …self.requestarguments,query_arguments,body_arguments,query,uri,path,headers,cookies, …The aiohttp route symbols are gathered in
_ROUTE_TABLESand_ROUTE_CALLS, so the entry points, the registrars and the request objects share one list. The models are the same.Engine
parameter_sources: with a request object, the parameters after the request are text._TaintProblem.attribute: an attribute read of a value whose every source is a request object listing the attribute removesNOSQL._TaintProblem.covered: the source covering a symbol, narrowed by the request attribute read below it. Without it,self.request.GETgot the full kinds back from theView.requestsource that covers its symbol. Both attribute reads and method calls use it._STRUCTURED(ALLwithoutTEXT_KINDS, that isNOSQL) is what text loses, in the scalar parameters of Detection: a nosql-injection rule for structured attacker input #158 too.Changed expectation
test_a_django_request_carries_nosql_as_a_wholedocumented the limit this PR lifts:request.GET["name"]was reported. It is replaced by tests where Django's text attributes and URL parameters are text and its body,read()and files stay payloads.Remaining limit
A helper function the request is passed to reads it as a whole. Function summaries do not know where their parameters come from.
test_a_helper_the_request_is_passed_to_reads_it_as_a_wholedocuments it.Verification
xssfromrequest.GETand a URL parameter);pytest: 1196 passed.pytest -m regression: 19 passed, unchanged.ruff checkandmypy: clean.nosql-injectionfindings. Three are false:request.GETplus a URL parameter insearch, andself.request.GETplusObjectId(pk)in a class-basedget, reported twice.json.loads(request.body)inloginandjson.loads(self.request.body)inpost.