Python: Add redirect modeling tests (flask/django)

This commit is contained in:
Rasmus Wriedt Larsen
2021-01-19 14:43:25 +01:00
parent efb872ad1e
commit 501e510622
3 changed files with 63 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound
from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound
# Not an XSS sink, since the Content-Type is not "text/html"
# FP reported in https://github.com/github/codeql-python-team/issues/38
@@ -18,15 +18,35 @@ def safe__manual_content_type(request):
# XSS FP reported in https://github.com/github/codeql/issues/3466
# Note: This should be an open-redirect sink, but not an XSS sink.
def or__redirect(request):
return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype=text/html
next = request.GET.get("next")
return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html MISSING: HttpRedirectResponse redirectLocation=next
def information_exposure_through_redirect(request, as_kw=False):
def information_exposure_through_redirect(request, as_kw=False, perm_redirect=False):
# This is a contrived example, but possible
private = "private"
next = request.GET.get("next")
if as_kw:
return HttpResponseRedirect(request.GET.get("next"), content=private) # $HttpResponse mimetype=text/html responseBody=private
return HttpResponseRedirect(next, content=private) # $HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next
else:
return HttpResponseRedirect(request.GET.get("next"), private) # $HttpResponse mimetype=text/html responseBody=private
return HttpResponseRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next
def perm_redirect(request):
private = "private"
next = request.GET.get("next")
return HttpResponsePermanentRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next
def redirect_through_normal_response(request):
private = "private"
next = request.GET.get("next")
resp = HttpResponse() # $ HttpResponse mimetype=text/html
resp.status_code = 302
resp['Location'] = next # $ MISSING: redirectLocation=next
resp.content = private # $ MISSING: responseBody=private
return resp
# Ensure that simple subclasses are still vuln to XSS
def xss__not_found(request):

View File

@@ -1,6 +1,6 @@
import json
from flask import Flask, make_response, jsonify, Response, request
from flask import Flask, make_response, jsonify, Response, request, redirect
app = Flask(__name__)
@@ -172,6 +172,18 @@ def app_response_class(): # $requestHandler
# TODO: add tests for setting status code
# TODO: add test that manually creates a redirect by setting status code and suitable header.
################################################################################
# Redirect
################################################################################
@app.route("/redirect-simple") # $routeSetup="/redirect-simple"
def redirect_simple(): # $requestHandler
next = request.args['next']
resp = redirect(next) # $ MISSING: HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next
return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp
################################################################################

View File

@@ -239,6 +239,31 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest {
}
}
class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest {
HttpServerHttpRedirectResponseTest() { this = "HttpServerHttpRedirectResponseTest" }
override string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
(
exists(HTTP::Server::HttpRedirectResponse redirect |
location = redirect.getLocation() and
element = redirect.toString() and
value = "" and
tag = "HttpRedirectResponse"
)
or
exists(HTTP::Server::HttpRedirectResponse redirect |
location = redirect.getLocation() and
element = redirect.toString() and
value = value_from_expr(redirect.getRedirectLocation().asExpr()) and
tag = "redirectLocation"
)
)
}
}
class FileSystemAccessTest extends InlineExpectationsTest {
FileSystemAccessTest() { this = "FileSystemAccessTest" }