mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
Python: Add redirect modeling tests (flask/django)
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
|
||||
@@ -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" }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user