Skip to main content

Server side template injection

Need

Prevention of server-side template injection attacks

Context

  • Usage of Scala for building scalable and high-performance applications
  • Usage of play.api.mvc for handling HTTP requests and responses in Play Framework
  • Usage of play.twirl.api.Html for generating HTML templates in Play Framework

Description

Non compliant code

import play.api.mvc._
import play.twirl.api.Html

class ApplicationController extends Controller {
def renderTemplate(userInput: String) = Action {
val template = s"<h1>Welcome, $userInput!</h1>"
Ok(Html(template))
}
}

The above Scala code represents a simple Play Framework application with a single action renderTemplate that takes a user input string, interpolates it into an HTML template, and then serves this template as a response.

The vulnerability lies in the fact that the user input is directly interpolated into the HTML template without any sanitization or escaping. This allows an attacker to inject arbitrary HTML or script code into the template. This code will then be executed when the template is served and rendered in the user's browser.

For example, an attacker could provide the following input:

<script>/* malicious script code */</script>

This would result in the following template:

<h1>Welcome, <script>/* malicious script code */</script>!</h1>

When this template is served and rendered in the user's browser, the malicious script code would be executed. This could lead to various types of attacks, such as stealing the user's cookies or performing actions on their behalf.

The vulnerability could be exploited to perform more serious attacks if the server-side application uses the template to perform server-side operations. For example, if the template is used to construct a command that is then executed on the server, an attacker could inject arbitrary command code into the template, leading to remote code execution on the server.

Steps

  • Sanitize user input: Validate and sanitize any user input before using it in a template. This can be done by using input validation techniques and ensuring that only safe characters are allowed.
  • Use parameterized templates: Instead of directly concatenating user input into the template string, use parameterized templates or template engines that automatically handle escaping and sanitization of user input.
  • Implement a strict content security policy: Configure the application to only allow trusted sources for templates and restrict the use of dynamic templates.
  • Regularly update dependencies: Keep all dependencies, including the Play framework and template engines, up to date to ensure that any security vulnerabilities are patched.
  • Perform security testing: Regularly conduct security testing, including penetration testing and code reviews, to identify and fix any potential vulnerabilities in the application.

Compliant code

import play.api.mvc._
import play.twirl.api.Html
import org.apache.commons.lang3.StringEscapeUtils

class ApplicationController extends Controller {
def renderTemplate(userInput: String) = Action {
val sanitizedInput = StringEscapeUtils.escapeHtml4(userInput)
val template = s"<h1>Welcome, $sanitizedInput!</h1>"
Ok(Html(template))
}
}

The updated code now includes a step to sanitize the user input before it is used in the template. This is done using the escapeHtml4 method from the Apache Commons Lang library, which will escape any HTML characters in the user input. This prevents any potential HTML injection attacks, as any HTML tags in the user input will be treated as literal text rather than being interpreted as HTML by the browser.

The escapeHtml4 method will replace characters like &lt; and > with their HTML escaped equivalents, &lt; and &gt; respectively. This means that if a user tries to input something like &lt;script>malicious code&lt;/script>, it will be rendered in the browser as &lt;script&gt;malicious code&lt;/script&gt;, which will be displayed as literal text rather than being executed as a script.

This is a simple and effective way to prevent server-side template injection attacks, as it ensures that user input cannot be used to inject malicious code into the template. However, it's important to note that this is just one layer of defense, and other security measures should also be implemented, such as using parameterized templates, implementing a strict content security policy, regularly updating dependencies, and conducting regular security testing.

References