diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt index cc126c5a..ce09a56f 100644 --- a/NEW_FEATURES.txt +++ b/NEW_FEATURES.txt @@ -50,6 +50,15 @@ Smarty 3.1.22 the setting of $static_classes will be checked. Note: That this security check is performed at compile time. + - trusted constants . + The Smarty_Security class has the new property $trusted_constants to restrict access to constants. + It's an array of trusted constant names. + Format: + array ( + 'SMARTY_DIR' , // allowed constant + } + If the array is empty (default) the usage of constants can be controlled with the + Smarty_Security::$allow_constants property (default true) diff --git a/change_log.txt b/change_log.txt index 2e770538..5a937a27 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,8 +1,8 @@  ===== 3.1.22-dev ===== (xx.xx.2015) - 23.03.2015 - - bugfix problems when {function}{/function} defined a template function in a cached subtemplate and it was called {call} - from a not cached subtemplate {forum topic 25468} - + 27.03.2015 + - bugfix Smarty_Security->allow_constants=false; did also disable true, false and null (change of 16.03.2015) + - improvement added a whitelist for trusted constants to security Smarty_Security::$trusted_constants (forum topic 25471) + 20.03.2015 - bugfix make sure that function properties get saved only in compiled files containing the fuction definition {forum topic 25452} - bugfix correct update of global variable values on exit of template functions. (reported under Smarty Developers) diff --git a/lexer/smarty_internal_templateparser.y b/lexer/smarty_internal_templateparser.y index 6ea97782..956d5321 100644 --- a/lexer/smarty_internal_templateparser.y +++ b/lexer/smarty_internal_templateparser.y @@ -486,8 +486,8 @@ smartytag(res) ::= LDEL varindexed(vi) EQUAL expr(e) attributes(a). { // tag with optional Smarty2 style attributes smartytag(res) ::= LDEL ID(i) attributes(a). { if (defined(i)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(i, $this->compiler); } res = $this->compiler->compileTag('private_print_expression',a,array('value'=>i)); } else { @@ -496,8 +496,8 @@ smartytag(res) ::= LDEL ID(i) attributes(a). { } smartytag(res) ::= LDEL ID(i). { if (defined(i)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(i, $this->compiler); } res = $this->compiler->compileTag('private_print_expression',array(),array('value'=>i)); } else { @@ -509,8 +509,8 @@ smartytag(res) ::= LDEL ID(i). { // tag with modifier and optional Smarty2 style attributes smartytag(res) ::= LDEL ID(i) modifierlist(l)attributes(a). { if (defined(i)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(i, $this->compiler); } res = $this->compiler->compileTag('private_print_expression',a,array('value'=>i, 'modifierlist'=>l)); } else { @@ -656,8 +656,8 @@ attributes(res) ::= . { // attribute attribute(res) ::= SPACE ID(v) EQUAL ID(id). { if (defined(id)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(id, $this->compiler); } res = array(v=>id); } else { @@ -880,8 +880,8 @@ value(res) ::= DOT INTEGER(n1). { // ID, true, false, null value(res) ::= ID(id). { if (defined(id)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(id, $this->compiler); } res = id; } else { @@ -1040,9 +1040,9 @@ indexdef(res) ::= DOT DOLLAR varvar(v) AT ID(p). { indexdef(res) ::= DOT ID(i). { if (defined(i)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); - } + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant(i, $this->compiler); + } res = "[". i ."]"; } else { res = "['". i ."']"; diff --git a/libs/sysplugins/smarty_internal_templateparser.php b/libs/sysplugins/smarty_internal_templateparser.php index bb8e1985..783a81a9 100644 --- a/libs/sysplugins/smarty_internal_templateparser.php +++ b/libs/sysplugins/smarty_internal_templateparser.php @@ -2549,8 +2549,8 @@ class Smarty_Internal_Templateparser function yy_r32() { if (defined($this->yystack[$this->yyidx + - 1]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + - 1]->minor, $this->compiler); } $this->_retvalue = $this->compiler->compileTag('private_print_expression', $this->yystack[$this->yyidx + 0]->minor, array('value' => $this->yystack[$this->yyidx + - 1]->minor)); } else { @@ -2562,8 +2562,8 @@ class Smarty_Internal_Templateparser function yy_r33() { if (defined($this->yystack[$this->yyidx + 0]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } $this->_retvalue = $this->compiler->compileTag('private_print_expression', array(), array('value' => $this->yystack[$this->yyidx + 0]->minor)); } else { @@ -2575,8 +2575,8 @@ class Smarty_Internal_Templateparser function yy_r34() { if (defined($this->yystack[$this->yyidx + - 2]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + - 2]->minor, $this->compiler); } $this->_retvalue = $this->compiler->compileTag('private_print_expression', $this->yystack[$this->yyidx + 0]->minor, array('value' => $this->yystack[$this->yyidx + - 2]->minor, 'modifierlist' => $this->yystack[$this->yyidx + - 1]->minor)); } else { @@ -2733,8 +2733,8 @@ class Smarty_Internal_Templateparser function yy_r61() { if (defined($this->yystack[$this->yyidx + 0]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } $this->_retvalue = array($this->yystack[$this->yyidx + - 2]->minor => $this->yystack[$this->yyidx + 0]->minor); } else { @@ -2891,8 +2891,8 @@ class Smarty_Internal_Templateparser function yy_r108() { if (defined($this->yystack[$this->yyidx + 0]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } $this->_retvalue = $this->yystack[$this->yyidx + 0]->minor; } else { @@ -3012,8 +3012,8 @@ class Smarty_Internal_Templateparser function yy_r133() { if (defined($this->yystack[$this->yyidx + 0]->minor)) { - if (isset($this->smarty->security_policy) && !$this->smarty->security_policy->allow_constants) { - $this->compiler->trigger_template_error("Security: access to constants not permitted"); + if (isset($this->smarty->security_policy)) { + $this->smarty->security_policy->isTrustedConstant($this->yystack[$this->yyidx + 0]->minor, $this->compiler); } $this->_retvalue = "[" . $this->yystack[$this->yyidx + 0]->minor . "]"; } else { diff --git a/libs/sysplugins/smarty_security.php b/libs/sysplugins/smarty_security.php index 64354f90..5a70c618 100644 --- a/libs/sysplugins/smarty_security.php +++ b/libs/sysplugins/smarty_security.php @@ -54,6 +54,12 @@ class Smarty_Security * @var array */ public $trusted_uri = array(); + /** + * List of trusted constants names + * + * @var array + */ + public $trusted_constants = array(); /** * This is an array of trusted static classes. * If empty access to all static classes is allowed. @@ -410,6 +416,33 @@ class Smarty_Security return false; // should not, but who knows what happens to the compiler in the future? } + /** + * Check if constants are enabled or trusted + * + * @param string $const contant name + * @param object $compiler compiler object + * + * @return bool + */ + public function isTrustedConstant($const, $compiler) + { + if (in_array($const, array('true', 'false', 'null'))) { + return true; + } + if (!empty($this->trusted_constants)) { + if (!in_array($const, $this->trusted_constants)) { + $compiler->trigger_template_error("Security: access to constant '{$const}' not permitted"); + return false; + } + return true; + } + if ($this->allow_constants) { + return true; + } + $compiler->trigger_template_error("Security: access to constants not permitted"); + return false; + } + /** * Check if stream is trusted. *