Sandbox

Sandbox provides a security layer that gives you control over which tags, PHP functions, methods, etc., can be used in templates. Thanks to the sandbox mode, you can safely collaborate with a client or external coder on template creation without worrying about compromising the application or performing unwanted operations.

How does it work? We simply define what we want to allow in the template. Initially, everything is forbidden and we gradually grant permissions. The following code allows the template author 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 individual 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 attempts to call a disallowed function or access a disallowed method or property, it throws a Latte\SecurityViolationException.

Creating a policy from scratch, where everything is forbidden, might not be convenient, so you can start from a secure baseline:

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

This secure baseline 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 except for datastream, noescape, and nocheck. Finally, access to the methods and properties of the $iterator object is allowed.

The rules apply to the template that we insert with the {sandbox} tag. This is somewhat analogous to {include}, but it enables sandbox mode and also does not pass any external variables:

{sandbox 'untrusted.latte'}

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

Some violations, like using a forbidden tag or filter, are detected at compile time. Others, like calling disallowed methods of an object, are detected at runtime. The template can also contain any other errors. To prevent an exception from the sandboxed template from disrupting the entire rendering process, you can define your own exception handler, which might, for example, just log it.

If we wanted to enable sandbox mode directly for all templates, it's easy:

$latte->setSandboxMode();

To ensure that a user doesn't insert PHP code into the page that is syntactically correct but forbidden and causes a PHP Compile Error, we recommend having templates checked by the PHP linter. You can activate this functionality using the Engine::enablePhpLint() method. Since it needs to call the PHP binary for the check, pass its path as a parameter:

$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');
version: 3.0