Skip to main content

Reflected cross-site scripting (XSS)

Need

Implementation of input validation and output encoding to prevent XSS attacks

Context

  • Usage of Python 3 for developing applications and scripts
  • Usage of Django for building web applications in Python

Description

Non compliant code

from django.http import HttpResponse
from django.views import View

class SearchView(View):
def get(self, request, *args, **kwargs):
search_query = request.GET.get('q', '')
return HttpResponse(f"Search results for: {search_query}")

The above code is a simple view in Django that takes a search query from the user and returns a response that includes the search query. The search query is taken directly from the GET parameters of the request (request.GET.get('q', '')) and is then directly included in the response (HttpResponse(f"Search results for: {search_query}")).

The problem with this code is that it doesn't validate or escape the search query before including it in the response. This means that if an attacker provides a search query that includes JavaScript code, that code will be included directly in the response and will be executed by the browser when the response is displayed. This is a classic example of a reflected cross-site scripting (XSS) vulnerability.

For example, an attacker could send a link to a victim that includes a search query like "><script>doSomethingEvil()</script>. If the victim clicks on the link, the JavaScript code in the search query will be executed in their browser.

Steps

  • Sanitize the input data: Use Django's built-in escaping functions to sanitize the 'search_query' before using it in the HttpResponse.
  • Use Django's template system: Instead of directly inserting the 'search_query' into the HttpResponse, use Django's template system which automatically escapes variables.
  • Apply Content Security Policy (CSP): Implement CSP to reduce the risk of XSS attacks by declaring which dynamic resources are allowed to load.
  • Use HTTPOnly and Secure flags: Set HTTPOnly and Secure flags for cookies to prevent them from being accessed by client-side scripts.

Compliant code

from django.http import HttpResponse
from django.shortcuts import render
from django.views import View

class SearchView(View):
def get(self, request, *args, **kwargs):
search_query = request.GET.get('q', '')
context = {'search_query': search_query}
return render(request, 'search_results.html', context)

The updated code now uses Django's built-in template system to render the search results. The render function takes in the request, the template name, and a context (which is a dictionary that maps template variable names to Python objects).

In the template, we use the escape filter to ensure that the search_query is properly escaped. This prevents any potentially malicious code from being executed.

This is a simple and effective way to prevent Reflected Cross-Site Scripting (XSS) attacks. However, it's important to note that this is just one layer of protection and other security measures should also be implemented.

For instance, you should also consider implementing a Content Security Policy (CSP) to control which dynamic resources are allowed to load on your site. This can help to mitigate the risk of XSS attacks.

Additionally, you should set the HTTPOnly and Secure flags for cookies. The HTTPOnly flag prevents cookies from being accessed by client-side scripts, while the Secure flag ensures that cookies are only sent over secure (HTTPS) connections.

References