libs/sysplugins/smarty_security.php Quellcode

smarty_security.php
gehe zur Dokumentation dieser Datei
1 <?php
10 /*
11  * FIXME: Smarty_Security API
12  * - getter and setter instead of public properties would allow cultivating an internal cache properly
13  * - current implementation of isTrustedResourceDir() assumes that Smarty::$template_dir and Smarty::$config_dir are immutable
14  * the cache is killed every time either of the variables change. That means that two distinct Smarty objects with differing
15  * $template_dir or $config_dir should NOT share the same Smarty_Security instance,
16  * as this would lead to (severe) performance penalty! how should this be handled?
17  */
18 
23 {
43  public $secure_dir = array();
50  public $trusted_dir = array();
56  public $trusted_uri = array();
62  public $trusted_constants = array();
70  public $static_classes = array();
71 
84  public $trusted_static_methods = array();
85 
98  public $trusted_static_properties = array();
106  public $php_functions = array(
107  'isset', 'empty',
108  'count', 'sizeof',
109  'in_array', 'is_array',
110  'time',
111  );
119  public $php_modifiers = array(
120  'escape',
121  'count',
122  'nl2br',
123  );
130  public $allowed_tags = array();
137  public $disabled_tags = array();
144  public $allowed_modifiers = array();
151  public $disabled_modifiers = array();
165  public $streams = array('file');
171  public $allow_constants = true;
177  public $allow_super_globals = true;
195  protected $_resource_dir = null;
201  protected $_template_dir = null;
207  protected $_config_dir = null;
213  protected $_secure_dir = null;
219  protected $_php_resource_dir = null;
225  protected $_trusted_dir = null;
226 
230  public function __construct($smarty)
231  {
232  $this->smarty = $smarty;
233  }
234 
244  public function isTrustedPhpFunction($function_name, $compiler)
245  {
246  if (isset($this->php_functions) && (empty($this->php_functions) || in_array($function_name, $this->php_functions))) {
247  return true;
248  }
249 
250  $compiler->trigger_template_error("PHP function '{$function_name}' not allowed by security setting");
251 
252  return false; // should not, but who knows what happens to the compiler in the future?
253  }
254 
264  public function isTrustedStaticClass($class_name, $compiler)
265  {
266  if (isset($this->static_classes) && (empty($this->static_classes) || in_array($class_name, $this->static_classes))) {
267  return true;
268  }
269 
270  $compiler->trigger_template_error("access to static class '{$class_name}' not allowed by security setting");
271 
272  return false; // should not, but who knows what happens to the compiler in the future?
273  }
274 
285  public function isTrustedStaticClassAccess($class_name, $params, $compiler)
286  {
287  if (!isset($params[2])) {
288  // fall back
289  return $this->isTrustedStaticClass($class_name, $compiler);
290  }
291  if ($params[2] == 'method') {
293  $name = substr($params[0], 0, strpos($params[0], '('));
294  } else {
296  // strip '$'
297  $name = substr($params[0], 1);
298  }
299  if (isset($allowed)) {
300  if (empty($allowed)) {
301  // fall back
302  return $this->isTrustedStaticClass($class_name, $compiler);
303  }
304  if (isset($allowed[$class_name])
305  && (empty($allowed[$class_name])
306  || in_array($name, $allowed[$class_name]))
307  ) {
308  return true;
309  }
310  }
311  $compiler->trigger_template_error("access to static class '{$class_name}' {$params[2]} '{$name}' not allowed by security setting");
312  return false; // should not, but who knows what happens to the compiler in the future?
313  }
314 
324  public function isTrustedPhpModifier($modifier_name, $compiler)
325  {
326  if (isset($this->php_modifiers) && (empty($this->php_modifiers) || in_array($modifier_name, $this->php_modifiers))) {
327  return true;
328  }
329 
330  $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting");
331 
332  return false; // should not, but who knows what happens to the compiler in the future?
333  }
334 
344  public function isTrustedTag($tag_name, $compiler)
345  {
346  // check for internal always required tags
347  if (in_array($tag_name, array('assign', 'call', 'private_filter', 'private_block_plugin', 'private_function_plugin', 'private_object_block_function',
348  'private_object_function', 'private_registered_function', 'private_registered_block', 'private_special_variable', 'private_print_expression', 'private_modifier'))
349  ) {
350  return true;
351  }
352  // check security settings
353  if (empty($this->allowed_tags)) {
354  if (empty($this->disabled_tags) || !in_array($tag_name, $this->disabled_tags)) {
355  return true;
356  } else {
357  $compiler->trigger_template_error("tag '{$tag_name}' disabled by security setting", $compiler->lex->taglineno);
358  }
359  } elseif (in_array($tag_name, $this->allowed_tags) && !in_array($tag_name, $this->disabled_tags)) {
360  return true;
361  } else {
362  $compiler->trigger_template_error("tag '{$tag_name}' not allowed by security setting", $compiler->lex->taglineno);
363  }
364 
365  return false; // should not, but who knows what happens to the compiler in the future?
366  }
367 
377  public function isTrustedSpecialSmartyVar($var_name, $compiler)
378  {
379  if (!in_array($var_name, $this->disabled_special_smarty_vars)) {
380  return true;
381  } else {
382  $compiler->trigger_template_error("special variable '\$smarty.{$var_name}' not allowed by security setting", $compiler->lex->taglineno);
383  }
384 
385  return false; // should not, but who knows what happens to the compiler in the future?
386  }
387 
397  public function isTrustedModifier($modifier_name, $compiler)
398  {
399  // check for internal always allowed modifier
400  if (in_array($modifier_name, array('default'))) {
401  return true;
402  }
403  // check security settings
404  if (empty($this->allowed_modifiers)) {
405  if (empty($this->disabled_modifiers) || !in_array($modifier_name, $this->disabled_modifiers)) {
406  return true;
407  } else {
408  $compiler->trigger_template_error("modifier '{$modifier_name}' disabled by security setting", $compiler->lex->taglineno);
409  }
410  } elseif (in_array($modifier_name, $this->allowed_modifiers) && !in_array($modifier_name, $this->disabled_modifiers)) {
411  return true;
412  } else {
413  $compiler->trigger_template_error("modifier '{$modifier_name}' not allowed by security setting", $compiler->lex->taglineno);
414  }
415 
416  return false; // should not, but who knows what happens to the compiler in the future?
417  }
418 
427  public function isTrustedConstant($const, $compiler)
428  {
429  if (in_array($const, array('true', 'false', 'null'))) {
430  return true;
431  }
432  if (!empty($this->trusted_constants)) {
433  if (!in_array($const, $this->trusted_constants)) {
434  $compiler->trigger_template_error("Security: access to constant '{$const}' not permitted");
435  return false;
436  }
437  return true;
438  }
439  if ($this->allow_constants) {
440  return true;
441  }
442  $compiler->trigger_template_error("Security: access to constants not permitted");
443  return false;
444  }
445 
454  public function isTrustedStream($stream_name)
455  {
456  if (isset($this->streams) && (empty($this->streams) || in_array($stream_name, $this->streams))) {
457  return true;
458  }
459 
460  throw new SmartyException("stream '{$stream_name}' not allowed by security setting");
461  }
462 
471  public function isTrustedResourceDir($filepath)
472  {
473  $_template = false;
474  $_config = false;
475  $_secure = false;
476 
477  $_template_dir = $this->smarty->getTemplateDir();
478  $_config_dir = $this->smarty->getConfigDir();
479 
480  // check if index is outdated
481  if ((!$this->_template_dir || $this->_template_dir !== $_template_dir)
482  || (!$this->_config_dir || $this->_config_dir !== $_config_dir)
483  || (!empty($this->secure_dir) && (!$this->_secure_dir || $this->_secure_dir !== $this->secure_dir))
484  ) {
485  $this->_resource_dir = array();
486  $_template = true;
487  $_config = true;
488  $_secure = !empty($this->secure_dir);
489  }
490 
491  // rebuild template dir index
492  if ($_template) {
493  $this->_template_dir = $_template_dir;
494  foreach ($_template_dir as $directory) {
495  $directory = realpath($directory);
496  $this->_resource_dir[$directory] = true;
497  }
498  }
499 
500  // rebuild config dir index
501  if ($_config) {
502  $this->_config_dir = $_config_dir;
503  foreach ($_config_dir as $directory) {
504  $directory = realpath($directory);
505  $this->_resource_dir[$directory] = true;
506  }
507  }
508 
509  // rebuild secure dir index
510  if ($_secure) {
511  $this->_secure_dir = $this->secure_dir;
512  foreach ((array) $this->secure_dir as $directory) {
513  $directory = realpath($directory);
514  $this->_resource_dir[$directory] = true;
515  }
516  }
517 
518  $_filepath = realpath($filepath);
519  $directory = dirname($_filepath);
520  $_directory = array();
521  while (true) {
522  // remember the directory to add it to _resource_dir in case we're successful
523  $_directory[$directory] = true;
524  // test if the directory is trusted
525  if (isset($this->_resource_dir[$directory])) {
526  // merge sub directories of current $directory into _resource_dir to speed up subsequent lookup
527  $this->_resource_dir = array_merge($this->_resource_dir, $_directory);
528 
529  return true;
530  }
531  // abort if we've reached root
532  if (($pos = strrpos($directory, DS)) === false || !isset($directory[1])) {
533  break;
534  }
535  // bubble up one level
536  $directory = substr($directory, 0, $pos);
537  }
538 
539  // give up
540  throw new SmartyException("directory '{$_filepath}' not allowed by security setting");
541  }
542 
555  public function isTrustedUri($uri)
556  {
557  $_uri = parse_url($uri);
558  if (!empty($_uri['scheme']) && !empty($_uri['host'])) {
559  $_uri = $_uri['scheme'] . '://' . $_uri['host'];
560  foreach ($this->trusted_uri as $pattern) {
561  if (preg_match($pattern, $_uri)) {
562  return true;
563  }
564  }
565  }
566 
567  throw new SmartyException("URI '{$uri}' not allowed by security setting");
568  }
569 
578  public function isTrustedPHPDir($filepath)
579  {
580  if (empty($this->trusted_dir)) {
581  throw new SmartyException("directory '{$filepath}' not allowed by security setting (no trusted_dir specified)");
582  }
583 
584  // check if index is outdated
585  if (!$this->_trusted_dir || $this->_trusted_dir !== $this->trusted_dir) {
586  $this->_php_resource_dir = array();
587 
588  $this->_trusted_dir = $this->trusted_dir;
589  foreach ((array) $this->trusted_dir as $directory) {
590  $directory = realpath($directory);
591  $this->_php_resource_dir[$directory] = true;
592  }
593  }
594 
595  $_filepath = realpath($filepath);
596  $directory = dirname($_filepath);
597  $_directory = array();
598  while (true) {
599  // remember the directory to add it to _resource_dir in case we're successful
600  $_directory[] = $directory;
601  // test if the directory is trusted
602  if (isset($this->_php_resource_dir[$directory])) {
603  // merge sub directories of current $directory into _resource_dir to speed up subsequent lookup
604  $this->_php_resource_dir = array_merge($this->_php_resource_dir, $_directory);
605 
606  return true;
607  }
608  // abort if we've reached root
609  if (($pos = strrpos($directory, DS)) === false || !isset($directory[2])) {
610  break;
611  }
612  // bubble up one level
613  $directory = substr($directory, 0, $pos);
614  }
615 
616  throw new SmartyException("directory '{$_filepath}' not allowed by security setting");
617  }
618 
626  public function startTemplate($template)
627  {
628  if ($this->max_template_nesting > 0 && $this->_current_template_nesting ++ >= $this->max_template_nesting) {
629  throw new SmartyException("maximum template nesting level of '{$this->max_template_nesting}' exceeded when calling '{$template->template_resource}'");
630  }
631  }
632 
638  public function exitTemplate($template)
639  {
640  if ($this->max_template_nesting > 0) {
641  $this->_current_template_nesting --;
642  }
643  }
644 }




Korrekturen, Hinweise und Ergänzungen

Bitte scheuen Sie sich nicht und melden Sie, was auf dieser Seite sachlich falsch oder irreführend ist, was ergänzt werden sollte, was fehlt usw. Dazu bitte oben aus dem Menü Seite den Eintrag Support Forum wählen. Es ist eine kostenlose Anmeldung erforderlich, um Anmerkungen zu posten. Unpassende Postings, Spam usw. werden kommentarlos entfernt.