Skip to main content

Server side template injection

Need

Prevention of server-side template injection attacks

Context

  • Usage of Python 3 for writing and executing Python code
  • Usage of Django for building web applications in Python

Description

Non compliant code

from django.template import Context, Template

def get_user_details(request):
user_id = request.GET.get('user_id')
t = Template('Hello, {{ user_id }}')
c = Context({'user_id': user_id})
return HttpResponse(t.render(c))

In the above code, the application is using Django's templating engine to generate a personalized greeting for a user based on their user ID. The user ID is passed in as a GET parameter in the HTTP request.

The vulnerability lies in the fact that the user ID is being inserted directly into the template without any form of sanitization or validation. This means that an attacker could potentially pass in a string that contains template syntax, which would then be executed by the server when the template is rendered.

For example, an attacker could pass in user_id={{ request.session.delete }}, which would delete the current session when the template is rendered, effectively logging the user out. This is a simple example, but the potential damage could be much more severe, depending on what other variables and methods are available in the template context.

This is a classic example of a Server Side Template Injection (SSTI) vulnerability, where user input is allowed to be injected directly into a server-side template, leading to potential remote code execution.

Steps

  • Validate and sanitize the user input. Ensure that the user_id is of the expected type and format before using it in the template.
  • Use Django's built-in template escaping to prevent any malicious code from being executed. This automatically escapes any variables used in the template.
  • Limit the use of user-supplied input in templates. If possible, avoid using user input directly in templates.
  • Implement a Content Security Policy (CSP) to reduce the risk of Cross-Site Scripting (XSS) attacks.
  • Regularly update and patch your server and its components to protect against known vulnerabilities.

Compliant code

from django.template import Context, Template
from django.core.validators import validate_integer
from django.core.exceptions import ValidationError

def get_user_details(request):
user_id = request.GET.get('user_id')

# Validate that user_id is an integer
try:
validate_integer(user_id)
except ValidationError:
return HttpResponse('Invalid user_id')

# Use Django's built-in template escaping
t = Template('Hello, {{ user_id }}')
c = Context({'user_id': user_id})
return HttpResponse(t.render(c))

The updated code includes a validation step to ensure that the user_id is an integer. This is done using Django's built-in validate_integer function. If the user_id is not an integer, a ValidationError is raised and an 'Invalid user_id' message is returned in the HTTP response.

The code continues to use Django's built-in template system, which automatically escapes any variables used in the template. This means that if a user tries to inject malicious code via the user_id, it will be escaped and not executed.

This code does not directly address the implementation of a Content Security Policy (CSP) or the regular updating and patching of your server and its components. These are important steps that should be taken as part of your overall security strategy, but they are outside the scope of this specific code snippet.

Remember, limiting the use of user-supplied input in templates and validating and sanitizing user input are key steps in preventing Server Side Template Injection (SSTI) vulnerabilities.

References