Sandbox

Latte has an armored stronghold directly under the hood. It is called sandbox mode and it is an important feature that protects applications that use templates from untrusted sources. For example, when they are edited by the users themselves.

Sandbox mode makes sure that the sand does not get out of the box. Thus, it provides limited access to tags, filters, functions, methods, etc. How does it work? We simply define what we want to allow in the template. In the beginning, everything is forbidden and we gradually grant permissions:

The following code allows the the template to use the {block}, {if}, {else} and {=} tags (the latter is a tag for printing a variable or expression) and all filters:

$policy = new Latte\Sandbox\SecurityPolicy;
$policy->allowTags(['block', 'if', 'else', '=']);
$policy->allowFilters($policy::All);

$latte->setPolicy($policy);

We can also allow access to global functions, methods or properties of objects:

$policy->allowFunctions(['trim', 'strlen']);
$policy->allowMethods(Nette\Security\User::class, ['isLoggedIn', 'isAllowed']);
$policy->allowProperties(Nette\Database\Row::class, $policy::All);

Isn't that amazing? You can control everything at a very low level. If the template tries to call an unauthorized function or access an unauthorized method or property, it throws exception Latte\SecurityViolationException.

Creating policies from scratch, when everything is forbidden, may not be convenient, so you can start from a safe foundation:

$policy = Latte\Sandbox\SecurityPolicy::createSafePolicy();

This means that all standard tags are allowed except for contentType, debugbreak, dump, extends, import, include, layout, php, sandbox, snippet, snippetArea, templatePrint, varPrint, widget. All standard filters are allowed as well except for datastream, noescape and nocheck. Finally, access to the methods and properties of object $iterator is allowed too.

The rules apply to the template that we insert with the new {sandbox} tag. Which is a something like {include}, but it turns on sandbox mode and also doesn't pass any external variables:

{sandbox 'untrusted.latte'}

Thus, the layout and individual pages can use all tags and variables as before, restrictions will be applied only to the template untrusted.latte.

Some violations, such as the use of a forbidden tag or filter, are detected at compile time. Others, such as calling unallowed methods of an object, at runtime. The template can also contain any other bugs. In order to prevent an exception from throwing from the sandboxed template, which disrupts the entire rendering, you can define your own exception handler, which, for example, just logs it.

If we want to turn on sandbox mode directly for all templates, it's easy:

$latte->setSandboxMode();