Skip to main content

Text-file templater

caution

Services need to be mocked within the context of (automated) testing.

Templating can be a very powerful tool for creating input dependent content. Packages like jinja2 greatly simplify the process of creating and rendering these templates:

>>> from jinja2 import Template
>>> template = Template('Hello {{ name }}!')
>>> template.render({'name': 'John Doe'})
'Hello John Doe!'

It consists of two parts:

  • the template: 'Hello {{ name }}!'
  • the context: {'name': 'John Doe'}

In some situations, both the template and the context will be strictly controlled by the developer: the template is a file in the repository and the developer creates a dictionary with the context from his own code.

In others, it might be beneficial to give the user more flexibility and let them create either the template or the context. An example use-case could be user defined reports in which the format varies a lot. Instead of figuring out all the logic, the user can create its own template.

This increase in flexibility however comes with a significant security risk which should be addressed.

Security risks

A templating engine combines the template with the context by defining a syntax. In the case of jinja2 this syntax is very extensive. It has for-loops, if-statements, variable assignment, to name a few.

All these possibilities make it very versatile and easy to for instance dump complete Python objects into the template and handle complex relations. This however also makes it possible to execute random Python logic. In more generic terms: jinja2 is turing complete, meaning that it is possible to write a complete computer program by just using the template and the context.

In the case of a developer controlled template and context, there is no problem: it is guaranteed that there will be no weird code injections taking place. This becomes problematic however when the template or the context is directly provided by the user or not strictly sanitized by the developer (e.g. inserting an input field directly into the template).

We do not want the user to execute its own created scripts directly on the server as it can do all sorts of harm.

render_jinja_template

Because of the possibility of code injection, it is necessary to run the rendering of the template in an isolated environment, often called a sandbox. Jinja2 provides such a sandbox in the library, but is has been circumvented a few times already. Instead, VIKTOR provides a render_jinja_template function which makes jinja templating easy and safe:

from viktor.utils import render_jinja_template

with open("path/to/template.jinja", 'rb') as template:
result = render_jinja_template(template, {'name': 'John Doe'})

This has the added benefit of not needing an extra dependency in your app.

note

This sandboxing has also been applied to the Word-file templater