Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

AbstractDynamicContentCheck.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 9.00 KiB


001  <?php
002   
003  /**
004  * @package   s9e\TextFormatter
005  * @copyright Copyright (c) 2010-2022 The s9e authors
006  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
007  */
008  namespace s9e\TextFormatter\Configurator\TemplateChecks;
009   
010  use DOMAttr;
011  use DOMElement;
012  use DOMNode;
013  use DOMXPath;
014  use s9e\TextFormatter\Configurator\Exceptions\UnsafeTemplateException;
015  use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
016  use s9e\TextFormatter\Configurator\Items\Attribute;
017  use s9e\TextFormatter\Configurator\Items\Tag;
018  use s9e\TextFormatter\Configurator\TemplateCheck;
019   
020  abstract class AbstractDynamicContentCheck extends TemplateCheck
021  {
022      /**
023      * @var bool Whether to ignore unknown attributes
024      */
025      protected $ignoreUnknownAttributes = false;
026   
027      /**
028      * Get the nodes targeted by this check
029      *
030      * @param  DOMElement $template <xsl:template/> node
031      * @return array             Array of DOMElement instances
032      */
033      abstract protected function getNodes(DOMElement $template);
034   
035      /**
036      * Return whether an attribute is considered safe
037      *
038      * @param  Attribute $attribute Attribute
039      * @return bool
040      */
041      abstract protected function isSafe(Attribute $attribute);
042   
043      /**
044      * Look for improperly-filtered dynamic content
045      *
046      * @param  DOMElement $template <xsl:template/> node
047      * @param  Tag        $tag      Tag this template belongs to
048      * @return void
049      */
050      public function check(DOMElement $template, Tag $tag)
051      {
052          foreach ($this->getNodes($template) as $node)
053          {
054              // Test this node's safety
055              $this->checkNode($node, $tag);
056          }
057      }
058   
059      /**
060      * Configure this template check to detect unknown attributes
061      *
062      * @return void
063      */
064      public function detectUnknownAttributes()
065      {
066          $this->ignoreUnknownAttributes = false;
067      }
068   
069      /**
070      * Configure this template check to ignore unknown attributes
071      *
072      * @return void
073      */
074      public function ignoreUnknownAttributes()
075      {
076          $this->ignoreUnknownAttributes = true;
077      }
078   
079      /**
080      * Test whether a tag attribute is safe
081      *
082      * @param  DOMNode $node     Context node
083      * @param  Tag     $tag      Source tag
084      * @param  string  $attrName Name of the attribute
085      * @return void
086      */
087      protected function checkAttribute(DOMNode $node, Tag $tag, $attrName)
088      {
089          // Test whether the attribute exists
090          if (!isset($tag->attributes[$attrName]))
091          {
092              if ($this->ignoreUnknownAttributes)
093              {
094                  return;
095              }
096   
097              throw new UnsafeTemplateException("Cannot assess the safety of unknown attribute '" . $attrName . "'", $node);
098          }
099   
100          // Test whether the attribute is safe to be used in this content type
101          if (!$this->tagFiltersAttributes($tag) || !$this->isSafe($tag->attributes[$attrName]))
102          {
103              throw new UnsafeTemplateException("Attribute '" . $attrName . "' is not properly sanitized to be used in this context", $node);
104          }
105      }
106   
107      /**
108      * Test whether an attribute expression is safe
109      *
110      * @param  DOMNode $node Context node
111      * @param  Tag     $tag  Source tag
112      * @param  string  $expr XPath expression that evaluates to one or multiple named attributes
113      * @return void
114      */
115      protected function checkAttributeExpression(DOMNode $node, Tag $tag, $expr)
116      {
117          preg_match_all('(@([-\\w]+))', $expr, $matches);
118          foreach ($matches[1] as $attrName)
119          {
120              $this->checkAttribute($node, $tag, $attrName);
121          }
122      }
123   
124      /**
125      * Test whether an attribute node is safe
126      *
127      * @param  DOMAttr $attribute Attribute node
128      * @param  Tag     $tag       Reference tag
129      * @return void
130      */
131      protected function checkAttributeNode(DOMAttr $attribute, Tag $tag)
132      {
133          // Parse the attribute value for XPath expressions and assess their safety
134          foreach (AVTHelper::parse($attribute->value) as $token)
135          {
136              if ($token[0] === 'expression')
137              {
138                  $this->checkExpression($attribute, $token[1], $tag);
139              }
140          }
141      }
142   
143      /**
144      * Test whether a node's context can be safely assessed
145      *
146      * @param  DOMNode $node Source node
147      * @return void
148      */
149      protected function checkContext(DOMNode $node)
150      {
151          // Test whether we know in what context this node is used. An <xsl:for-each/> ancestor would // change this node's context
152          $xpath     = new DOMXPath($node->ownerDocument);
153          $ancestors = $xpath->query('ancestor::xsl:for-each', $node);
154   
155          if ($ancestors->length)
156          {
157              throw new UnsafeTemplateException("Cannot assess context due to '" . $ancestors->item(0)->nodeName . "'", $node);
158          }
159      }
160   
161      /**
162      * Test whether an <xsl:copy-of/> node is safe
163      *
164      * @param  DOMElement $node <xsl:copy-of/> node
165      * @param  Tag        $tag  Reference tag
166      * @return void
167      */
168      protected function checkCopyOfNode(DOMElement $node, Tag $tag)
169      {
170          $this->checkSelectNode($node->getAttributeNode('select'), $tag);
171      }
172   
173      /**
174      * Test whether an element node is safe
175      *
176      * @param  DOMElement $element Element
177      * @param  Tag        $tag     Reference tag
178      * @return void
179      */
180      protected function checkElementNode(DOMElement $element, Tag $tag)
181      {
182          $xpath = new DOMXPath($element->ownerDocument);
183   
184          // If current node is not an <xsl:attribute/> element, we exclude descendants
185          // with an <xsl:attribute/> ancestor so that content such as:
186          //   <script><xsl:attribute name="id"><xsl:value-of/></xsl:attribute></script>
187          // would not trigger a false-positive due to the presence of an <xsl:value-of/>
188          // element in a <script>
189          $predicate = ($element->localName === 'attribute') ? '' : '[not(ancestor::xsl:attribute)]';
190   
191          // Test the select expression of <xsl:value-of/> nodes
192          $query = './/xsl:value-of' . $predicate;
193          foreach ($xpath->query($query, $element) as $valueOf)
194          {
195              $this->checkSelectNode($valueOf->getAttributeNode('select'), $tag);
196          }
197   
198          // Reject all <xsl:apply-templates/> nodes
199          $query = './/xsl:apply-templates' . $predicate;
200          foreach ($xpath->query($query, $element) as $applyTemplates)
201          {
202              throw new UnsafeTemplateException('Cannot allow unfiltered data in this context', $applyTemplates);
203          }
204      }
205   
206      /**
207      * Test the safety of an XPath expression
208      *
209      * @param  DOMNode $node Source node
210      * @param  string  $expr XPath expression
211      * @param  Tag     $tag  Source tag
212      * @return void
213      */
214      protected function checkExpression(DOMNode $node, $expr, Tag $tag)
215      {
216          $this->checkContext($node);
217   
218          if (preg_match('/^\\$(\\w+)$/', $expr, $m))
219          {
220              // Either this expression came from a variable that is considered safe, or it's a
221              // stylesheet parameters, which are considered safe by default
222              $this->checkVariable($node, $tag, $m[1]);
223          }
224          elseif (preg_match('/^@[-\\w]+(?:\\s*\\|\\s*@[-\\w]+)*$/', $expr))
225          {
226              $this->checkAttributeExpression($node, $tag, $expr);
227          }
228          elseif (!$this->isExpressionSafe($expr))
229          {
230              throw new UnsafeTemplateException("Cannot assess the safety of expression '" . $expr . "'", $node);
231          }
232      }
233   
234      /**
235      * Test whether a node is safe
236      *
237      * @param  DOMNode $node Source node
238      * @param  Tag     $tag  Reference tag
239      * @return void
240      */
241      protected function checkNode(DOMNode $node, Tag $tag)
242      {
243          if ($node instanceof DOMAttr)
244          {
245              $this->checkAttributeNode($node, $tag);
246          }
247          elseif ($node instanceof DOMElement)
248          {
249              if ($node->namespaceURI === self::XMLNS_XSL && $node->localName === 'copy-of')
250              {
251                  $this->checkCopyOfNode($node, $tag);
252              }
253              else
254              {
255                  $this->checkElementNode($node, $tag);
256              }
257          }
258      }
259   
260      /**
261      * Check whether a variable is safe in context
262      *
263      * @param  DOMNode $node  Context node
264      * @param  Tag     $tag   Source tag
265      * @param  string  $qname Name of the variable
266      * @return void
267      */
268      protected function checkVariable(DOMNode $node, $tag, $qname)
269      {
270          // Test whether this variable comes from a previous xsl:param or xsl:variable element
271          $this->checkVariableDeclaration($node, $tag, 'xsl:param[@name="' . $qname . '"]');
272          $this->checkVariableDeclaration($node, $tag, 'xsl:variable[@name="' . $qname . '"]');
273      }
274   
275      /**
276      * Check whether a variable declaration is safe in context
277      *
278      * @param  DOMNode $node  Context node
279      * @param  Tag     $tag   Source tag
280      * @param  string  $query XPath query
281      * @return void
282      */
283      protected function checkVariableDeclaration(DOMNode $node, $tag, $query)
284      {
285          $query = 'ancestor-or-self::*/preceding-sibling::' . $query . '[@select]';
286          $xpath = new DOMXPath($node->ownerDocument);
287          foreach ($xpath->query($query, $node) as $varNode)
288          {
289              // Intercept the UnsafeTemplateException and change the node to the one we're
290              // really checking before rethrowing it
291              try
292              {
293                  $this->checkExpression($varNode, $varNode->getAttribute('select'), $tag);
294              }
295              catch (UnsafeTemplateException $e)
296              {
297                  $e->setNode($node);
298   
299                  throw $e;
300              }
301          }
302      }
303   
304      /**
305      * Test whether a select attribute of a node is safe
306      *
307      * @param  DOMAttr $select Select attribute node
308      * @param  Tag     $tag    Reference tag
309      * @return void
310      */
311      protected function checkSelectNode(DOMAttr $select, Tag $tag)
312      {
313          $this->checkExpression($select, $select->value, $tag);
314      }
315   
316      /**
317      * Test whether given expression is safe in context
318      *
319      * @param  string $expr XPath expression
320      * @return bool         Whether the expression is safe in context
321      */
322      protected function isExpressionSafe($expr)
323      {
324          return false;
325      }
326   
327      /**
328      * Test whether given tag filters attribute values
329      *
330      * @param  Tag  $tag
331      * @return bool
332      */
333      protected function tagFiltersAttributes(Tag $tag)
334      {
335          return $tag->filterChain->containsCallback('s9e\\TextFormatter\\Parser\\FilterProcessing::filterAttributes');
336      }
337  }