new feature: security can now control access to static methods and properties

see also NEW_FEATURES.txt
This commit is contained in:
Uwe Tews
2015-01-22 03:53:01 +01:00
parent ec19bc763f
commit 1a781b39b1
5 changed files with 2469 additions and 2657 deletions

View File

@@ -24,6 +24,33 @@ Smarty 3.1.22
The main template is level 1. The nesting level is checked at run time. When the maximum will be exceeded The main template is level 1. The nesting level is checked at run time. When the maximum will be exceeded
an Exception will be thrown. The default setting is 0 which does disable this check. an Exception will be thrown. The default setting is 0 which does disable this check.
- trusted static methods -
The Smarty_Security class has the new property $trusted_static_methods to restrict access to static methods.
It's an nested array of trusted class and method names.
Format:
array (
'class_1' => array('method_1', 'method_2'), // allowed methods
'class_2' => array(), // all methods of class allowed
)
To disable access for all methods of all classes set $trusted_static_methods = null;
The default value is an empty array() which does enables all methods of all classes, but for backward compatibility
the setting of $static_classes will be checked.
- trusted static properties -
The Smarty_Security class has the new property $trusted_static_properties to restrict access to static properties.
It's an nested array of trusted class and property names.
Format:
array (
'class_1' => array('prop_1', 'prop_2'), // allowed properties listed
'class_2' => array(), // all properties of class allowed
}
To disable access for all properties of all classes set $trusted_static_properties = null;
The default value is an empty array() which does enables all properties of all classes, but for backward compatibility
the setting of $static_classes will be checked.
Compiled Templates Compiled Templates
================== ==================
Smarty does now automatically detect a change of the $merge_compiled_includes and $escape_html Smarty does now automatically detect a change of the $merge_compiled_includes and $escape_html

View File

@@ -1,5 +1,8 @@
 ===== 3.1.22-dev ===== (xx.xx.2015)  ===== 3.1.22-dev ===== (xx.xx.2015)
22.01.2015
- new feature security can now control access to static methods and properties
see also NEW_FEATURES.txt
21.01.2015 21.01.2015
- bugfix clearCompiledTemplates(), clearAll() and clear() could try to delete whole drive at wrong path permissions because realpath() fail (forum 25397) - bugfix clearCompiledTemplates(), clearAll() and clear() could try to delete whole drive at wrong path permissions because realpath() fail (forum 25397)
- bugfix 'self::' and 'parent::' was interpreted in template syntax as static class - bugfix 'self::' and 'parent::' was interpreted in template syntax as static class

View File

@@ -902,7 +902,7 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
} else { } else {
$this->compiler->prefix_code[] = '<?php $_tmp'.self::$prefix_number.' = '. $this->compileVariable(vi['var']).vi['smarty_internal_index'].';?>'; $this->compiler->prefix_code[] = '<?php $_tmp'.self::$prefix_number.' = '. $this->compileVariable(vi['var']).vi['smarty_internal_index'].';?>';
} }
res = '$_tmp'.self::$prefix_number.'::'.r; res = '$_tmp'.self::$prefix_number.'::'.r[0].r[1];
} }
@@ -924,11 +924,11 @@ value(res) ::= NAMESPACE(c). {
// static class access // static class access
value(res) ::= ns1(c)DOUBLECOLON static_class_access(s). { value(res) ::= ns1(c)DOUBLECOLON static_class_access(s). {
if (!in_array(strtolower(c), array('self', 'parent')) && (!$this->security || isset($this->smarty->registered_classes[c]) || $this->smarty->security_policy->isTrustedStaticClass(c, $this->compiler))) { if (!in_array(strtolower(c), array('self', 'parent')) && (!$this->security || $this->smarty->security_policy->isTrustedStaticClassAccess(c, s, $this->compiler))) {
if (isset($this->smarty->registered_classes[c])) { if (isset($this->smarty->registered_classes[c])) {
res = $this->smarty->registered_classes[c].'::'.s; res = $this->smarty->registered_classes[c].'::'.s[0].s[1];
} else { } else {
res = c.'::'.s; res = c.'::'.s[0].s[1];
} }
} else { } else {
$this->compiler->trigger_template_error ("static class '".c."' is undefined or not allowed by security setting"); $this->compiler->trigger_template_error ("static class '".c."' is undefined or not allowed by security setting");
@@ -1256,27 +1256,27 @@ modparameter(res) ::= COLON array(mp). {
// static class methode call // static class methode call
static_class_access(res) ::= method(m). { static_class_access(res) ::= method(m). {
res = m; res = array(m, '', 'method');
} }
// static class methode call with object chainig // static class methode call with object chainig
static_class_access(res) ::= method(m) objectchain(oc). { static_class_access(res) ::= method(m) objectchain(oc). {
res = m.oc; res = array(m, oc, 'method');
} }
// static class constant // static class constant
static_class_access(res) ::= ID(v). { static_class_access(res) ::= ID(v). {
res = v; res = array(v, '');
} }
// static class variables // static class variables
static_class_access(res) ::= DOLLAR ID(v) arrayindex(a). { static_class_access(res) ::= DOLLAR ID(v) arrayindex(a). {
res = '$'.v.a; res = array('$'.v, a, 'property');
} }
// static class variables with object chain // static class variables with object chain
static_class_access(res) ::= DOLLAR ID(v) arrayindex(a) objectchain(oc). { static_class_access(res) ::= DOLLAR ID(v) arrayindex(a) objectchain(oc). {
res = '$'.v.a.oc; res = array('$'.v, a.oc, 'property');
} }

File diff suppressed because it is too large Load Diff

View File

@@ -62,6 +62,34 @@ class Smarty_Security
* @var array * @var array
*/ */
public $static_classes = array(); public $static_classes = array();
/**
* This is an nested array of trusted classes and static methods.
* If empty access to all static classes and methods is allowed.
* Format:
* array (
* 'class_1' => array('method_1', 'method_2'), // allowed methods listed
* 'class_2' => array(), // all methods of class allowed
* )
* If set to null none is allowed.
*
* @var array
*/
public $trusted_static_methods = array();
/**
* This is an array of trusted static properties.
* If empty access to all static classes and properties is allowed.
* Format:
* array (
* 'class_1' => array('prop_1', 'prop_2'), // allowed properties listed
* 'class_2' => array(), // all properties of class allowed
* )
* If set to null none is allowed.
*
* @var array
*/
public $trusted_static_properties = array();
/** /**
* This is an array of trusted PHP functions. * This is an array of trusted PHP functions.
* If empty all functions are allowed. * If empty all functions are allowed.
@@ -238,6 +266,46 @@ class Smarty_Security
return false; // should not, but who knows what happens to the compiler in the future? return false; // should not, but who knows what happens to the compiler in the future?
} }
/**
* Check if static class method/property is trusted.
*
* @param string $class_name
* @param string $params
* @param object $compiler compiler object
*
* @return boolean true if class method is trusted
* @throws SmartyCompilerException if static class method is not trusted
*/
public function isTrustedStaticClassAccess($class_name, $params, $compiler)
{
if (!isset($params[2])) {
// fall back
return $this->isTrustedStaticClass($class_name, $compiler);
}
if ($params[2] == 'method') {
$allowed = $this->trusted_static_methods;
$name = substr($params[0], 0, strpos($params[0], '('));
} else {
$allowed = $this->trusted_static_properties;
// strip '$'
$name = substr($params[0], 1);
}
if (isset($allowed)) {
if (empty($allowed)) {
// fall back
return $this->isTrustedStaticClass($class_name, $compiler);
}
if (isset($allowed[$class_name])
&& (empty($allowed[$class_name])
|| in_array($name, $allowed[$class_name]))
) {
return true;
}
}
$compiler->trigger_template_error("access to static class '{$class_name}' {$params[2]} '{$name}' not allowed by security setting");
return false; // should not, but who knows what happens to the compiler in the future?
}
/** /**
* Check if PHP modifier is trusted. * Check if PHP modifier is trusted.
* *
@@ -290,6 +358,7 @@ class Smarty_Security
return false; // should not, but who knows what happens to the compiler in the future? return false; // should not, but who knows what happens to the compiler in the future?
} }
/** /**
* Check if special $smarty variable is trusted. * Check if special $smarty variable is trusted.
* *
@@ -521,8 +590,9 @@ class Smarty_Security
* *
* @throws SmartyException * @throws SmartyException
*/ */
public function startTemplate($template) { public function startTemplate($template)
if ($this->max_template_nesting > 0 && $this->_current_template_nesting++ >= $this->max_template_nesting) { {
if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) {
throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'"); throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'");
} }
} }
@@ -532,7 +602,8 @@ class Smarty_Security
* *
* @param $template * @param $template
*/ */
public function exitTemplate($template) { public function exitTemplate($template)
{
if ($this->max_template_nesting > 0) { if ($this->max_template_nesting > 0) {
$this->_current_template_nesting --; $this->_current_template_nesting --;
} }