bug #3349 Add test to verify that filter is not working when template_from_string (Bozhidar Hristov, fabpot)

This PR was merged into the 1.x branch.

Discussion
----------

Add test to verify that filter is not working when template_from_string

When using {{ include(sandboxed = true) }} in  conjunction with {{ template_from_string() }} - sandbox is not active.

Commits
-------

c7be1bb3 Fix sandbox support when using include(template_from_string())
04431228 Add test to verify that filter is not working when template_from_string is used.
This commit is contained in:
Fabien Potencier
2020-08-23 17:53:39 +02:00
7 changed files with 64 additions and 6 deletions
+1
View File
@@ -1,5 +1,6 @@
# 1.44.0 (2020-XX-XX)
* Fix sandbox support when using "include(template_from_string())"
* Make round brackets optional for one argument tests like "same as" or "divisible by"
* Add support for ES2015 style object initialisation shortcut { a } is the same as { 'a': a }
+7
View File
@@ -313,6 +313,8 @@ use Twig\Loader\SourceContextLoaderInterface;
use Twig\Markup;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Node;
use Twig\Template;
use Twig\TemplateWrapper;
/**
* Cycles over a value.
@@ -1562,6 +1564,11 @@ function twig_include(Environment $env, $context, $template, $variables = [], $w
}
}
// if a Template instance is passed, it might have been instantiated outside of a sandbox, check security
if ($template instanceof TemplateWrapper || $template instanceof Template) {
$template->unwrap()->checkSecurity();
}
$loaded = null;
try {
$loaded = $env->resolveTemplate($template);
+28
View File
@@ -0,0 +1,28 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node;
use Twig\Compiler;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
class CheckSecurityCallNode extends Node
{
public function compile(Compiler $compiler)
{
$compiler
->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n")
->write("\$this->checkSecurity();\n")
;
}
}
+9 -4
View File
@@ -45,10 +45,13 @@ class CheckSecurityNode extends Node
}
$compiler
->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n")
->write('$tags = ')->repr(array_filter($tags))->raw(";\n")
->write('$filters = ')->repr(array_filter($filters))->raw(";\n")
->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n")
->write("\n")
->write("public function checkSecurity()\n")
->write("{\n")
->indent()
->write('static $tags = ')->repr(array_filter($tags))->raw(";\n")
->write('static $filters = ')->repr(array_filter($filters))->raw(";\n")
->write('static $functions = ')->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->sandbox->checkSecurity(\n")
@@ -78,6 +81,8 @@ class CheckSecurityNode extends Node
->write("throw \$e;\n")
->outdent()
->write("}\n\n")
->outdent()
->write("}\n")
;
}
}
+3 -1
View File
@@ -12,6 +12,7 @@
namespace Twig\NodeVisitor;
use Twig\Environment;
use Twig\Node\CheckSecurityCallNode;
use Twig\Node\CheckSecurityNode;
use Twig\Node\CheckToStringNode;
use Twig\Node\Expression\Binary\ConcatBinary;
@@ -102,7 +103,8 @@ class SandboxNodeVisitor extends AbstractNodeVisitor
if ($node instanceof ModuleNode) {
$this->inAModule = false;
$node->getNode('constructor_end')->setNode('_security_check', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('display_start')]));
$node->setNode('constructor_end', new Node([new CheckSecurityCallNode(), $node->getNode('constructor_end')]));
$node->setNode('class_end', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('class_end')]));
} elseif ($this->inAModule) {
if ($node instanceof PrintNode || $node instanceof SetNode) {
$this->needsToStringWrap = false;
+1 -1
View File
@@ -397,7 +397,7 @@ abstract class Template implements \Twig_TemplateInterface
*
* @return Template
*/
protected function unwrap()
public function unwrap()
{
return $this;
}
+15
View File
@@ -14,6 +14,7 @@ namespace Twig\Tests\Extension;
use Twig\Environment;
use Twig\Error\SyntaxError;
use Twig\Extension\SandboxExtension;
use Twig\Extension\StringLoaderExtension;
use Twig\Loader\ArrayLoader;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityPolicy;
@@ -44,6 +45,7 @@ class SandboxTest extends \PHPUnit\Framework\TestCase
'1_layout' => '{% block content %}{% endblock %}',
'1_child' => "{% extends \"1_layout\" %}\n{% block content %}\n{{ \"a\"|json_encode }}\n{% endblock %}",
'1_include' => '{{ include("1_basic1", sandboxed=true) }}',
'1_basic2_include_template_from_string' => '{{ include(template_from_string("{{ name|upper }}"), sandboxed=true) }}',
'1_range_operator' => '{{ (1..2)[0] }}',
'1_syntax_error_wrapper' => '{% sandbox %}{% include "1_syntax_error" %}{% endsandbox %}',
'1_syntax_error' => '{% syntax error }}',
@@ -90,6 +92,19 @@ class SandboxTest extends \PHPUnit\Framework\TestCase
}
}
public function testSandboxUnallowedFilterWithIncludeTemplateFromString()
{
$twig = $this->getEnvironment(false, [], self::$templates);
$twig->addExtension(new StringLoaderExtension());
try {
$twig->load('1_basic2_include_template_from_string')->render(self::$params);
$this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
} catch (SecurityError $e) {
$this->assertInstanceOf('\Twig\Sandbox\SecurityNotAllowedFilterError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFilterError');
$this->assertEquals('upper', $e->getFilterName(), 'Exception should be raised on the "upper" filter');
}
}
public function testSandboxUnallowedFilter()
{
$twig = $this->getEnvironment(true, [], self::$templates);