Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Static Public Member Functions | Data Fields | Static Protected Member Functions
Zend_Xml_Security Class Reference

Static Public Member Functions

static loadXmlErrorHandler ($errno, $errstr, $errfile, $errline)
 
static scan ($xml, DOMDocument $dom=null)
 
static scanFile ($file, DOMDocument $dom=null)
 
static isPhpFpm ()
 
static generateEntityComparison ($encoding)
 
static encodeToUTF32BE ($ascii)
 
static encodeToUTF32LE ($ascii)
 
static encodeToUTF32odd1 ($ascii)
 
static encodeToUTF32odd2 ($ascii)
 
static encodeToUTF16BE ($ascii)
 
static encodeToUTF16LE ($ascii)
 
static encodeToUTF8 ($ascii)
 

Data Fields

const ENTITY_DETECT = 'Detected use of ENTITY in XML, disabled to prevent XXE/XEE attacks'
 

Static Protected Member Functions

static heuristicScan ($xml)
 
static getEntityComparison ($xml)
 
static detectStringEncoding ($xml)
 
static detectBom ($string)
 
static detectXmlStringEncoding ($xml)
 
static detectXmlEncoding ($xml, $fileEncoding)
 
static getBomMap ()
 
static getAsciiEncodingMap ()
 
static substr ($string, $start, $end)
 

Detailed Description

Definition at line 29 of file Security.php.

Member Function Documentation

◆ detectBom()

static detectBom (   $string)
staticprotected

Attempt to match a known BOM.

Iterates through the return of getBomMap(), comparing the initial bytes of the provided string to the BOM of each; if a match is determined, it returns the encoding.

Parameters
string$string
Returns
false|string Returns encoding on success.

Definition at line 223 of file Security.php.

224  {
225  foreach (self::getBomMap() as $criteria) {
226  if (0 === strncmp($string, $criteria['bom'], $criteria['length'])) {
227  return $criteria['encoding'];
228  }
229  }
230  return false;
231  }

◆ detectStringEncoding()

static detectStringEncoding (   $xml)
staticprotected

Determine the string encoding.

Determines string encoding from either a detected BOM or a heuristic.

Parameters
string$xml
Returns
string File encoding

Definition at line 207 of file Security.php.

208  {
209  $encoding = self::detectBom($xml);
210  return ($encoding) ? $encoding : self::detectXmlStringEncoding($xml);
211  }
static detectXmlStringEncoding($xml)
Definition: Security.php:239
static detectBom($string)
Definition: Security.php:223

◆ detectXmlEncoding()

static detectXmlEncoding (   $xml,
  $fileEncoding 
)
staticprotected

Attempt to detect the specified XML encoding.

Using the file's encoding, determines if an "encoding" attribute is present and well-formed in the XML declaration; if so, it returns a list with both the ASCII representation of that declaration and the original file encoding.

If not, a list containing only the provided file encoding is returned.

Parameters
string$xml
string$fileEncoding
Returns
string[] Potential XML encodings

Definition at line 266 of file Security.php.

267  {
268  $encodingMap = self::getAsciiEncodingMap();
269  $generator = $encodingMap[$fileEncoding];
270  $encAttr = call_user_func($generator, 'encoding="');
272  $close = call_user_func($generator, '>');
273 
274  $closePos = strpos($xml, $close);
275  if (false === $closePos) {
276  return array($fileEncoding);
277  }
278 
279  $encPos = strpos($xml, $encAttr);
280  if (false === $encPos
281  || $encPos > $closePos
282  ) {
283  return array($fileEncoding);
284  }
285 
286  $encPos += strlen($encAttr);
287  $quotePos = strpos($xml, $quote, $encPos);
288  if (false === $quotePos) {
289  return array($fileEncoding);
290  }
291 
292  $encoding = self::substr($xml, $encPos, $quotePos);
293  return array(
294  // Following line works because we're only supporting 8-bit safe encodings at this time.
295  str_replace('\0', '', $encoding), // detected encoding
296  $fileEncoding, // file encoding
297  );
298  }
static substr($string, $start, $end)
Definition: Security.php:379
$quote
static getAsciiEncodingMap()
Definition: Security.php:354

◆ detectXmlStringEncoding()

static detectXmlStringEncoding (   $xml)
staticprotected

Attempt to detect the string encoding of an XML string.

Parameters
string$xml
Returns
string Encoding

Definition at line 239 of file Security.php.

240  {
241  foreach (self::getAsciiEncodingMap() as $encoding => $generator) {
242  $prefix = call_user_func($generator, '<' . '?xml');
243  if (0 === strncmp($xml, $prefix, strlen($prefix))) {
244  return $encoding;
245  }
246  }
247 
248  // Fallback
249  return 'UTF-8';
250  }
$prefix
Definition: name.phtml:25

◆ encodeToUTF16BE()

static encodeToUTF16BE (   $ascii)
static

Encode an ASCII string to UTF-16BE

Definition at line 460 of file Security.php.

461  {
462  return preg_replace('/(.)/', "\0\\1", $ascii);
463  }

◆ encodeToUTF16LE()

static encodeToUTF16LE (   $ascii)
static

Encode an ASCII string to UTF-16LE

Definition at line 472 of file Security.php.

473  {
474  return preg_replace('/(.)/', "\\1\0", $ascii);
475  }

◆ encodeToUTF32BE()

static encodeToUTF32BE (   $ascii)
static

Encode an ASCII string to UTF-32BE

Definition at line 412 of file Security.php.

413  {
414  return preg_replace('/(.)/', "\0\0\0\\1", $ascii);
415  }

◆ encodeToUTF32LE()

static encodeToUTF32LE (   $ascii)
static

Encode an ASCII string to UTF-32LE

Definition at line 424 of file Security.php.

425  {
426  return preg_replace('/(.)/', "\\1\0\0\0", $ascii);
427  }

◆ encodeToUTF32odd1()

static encodeToUTF32odd1 (   $ascii)
static

Encode an ASCII string to UTF-32odd1

Definition at line 436 of file Security.php.

437  {
438  return preg_replace('/(.)/', "\0\\1\0\0", $ascii);
439  }

◆ encodeToUTF32odd2()

static encodeToUTF32odd2 (   $ascii)
static

Encode an ASCII string to UTF-32odd2

Definition at line 448 of file Security.php.

449  {
450  return preg_replace('/(.)/', "\0\0\\1\0", $ascii);
451  }

◆ encodeToUTF8()

static encodeToUTF8 (   $ascii)
static

Encode an ASCII string to UTF-8

Definition at line 484 of file Security.php.

485  {
486  return $ascii;
487  }

◆ generateEntityComparison()

static generateEntityComparison (   $encoding)
static

Generate an entity comparison based on the given encoding.

This patch is internal only, and public only so it can be used as a callable to pass to array_map.

Definition at line 398 of file Security.php.

399  {
400  $encodingMap = self::getAsciiEncodingMap();
401  $generator = isset($encodingMap[$encoding]) ? $encodingMap[$encoding] : $encodingMap['UTF-8'];
402  return call_user_func($generator, '<!ENTITY');
403  }
static getAsciiEncodingMap()
Definition: Security.php:354

◆ getAsciiEncodingMap()

static getAsciiEncodingMap ( )
staticprotected

Return a map of encoding => generator pairs.

Returns a map of encoding => generator pairs, where the generator is a callable that accepts a string and returns the appropriate byte order sequence of that string for the encoding.

Returns
array

Definition at line 354 of file Security.php.

355  {
356  return array(
357  'UTF-32BE' => array(__CLASS__, 'encodeToUTF32BE'),
358  'UTF-32LE' => array(__CLASS__, 'encodeToUTF32LE'),
359  'UTF-32odd1' => array(__CLASS__, 'encodeToUTF32odd1'),
360  'UTF-32odd2' => array(__CLASS__, 'encodeToUTF32odd2'),
361  'UTF-16BE' => array(__CLASS__, 'encodeToUTF16BE'),
362  'UTF-16LE' => array(__CLASS__, 'encodeToUTF16LE'),
363  'UTF-8' => array(__CLASS__, 'encodeToUTF8'),
364  'GB-18030' => array(__CLASS__, 'encodeToUTF8'),
365  );
366  }

◆ getBomMap()

static getBomMap ( )
staticprotected

Return a list of BOM maps.

Returns a list of common encoding -> BOM maps, along with the character length to compare against.

array

Definition at line 309 of file Security.php.

310  {
311  return array(
312  array(
313  'encoding' => 'UTF-32BE',
314  'bom' => pack('CCCC', 0x00, 0x00, 0xfe, 0xff),
315  'length' => 4,
316  ),
317  array(
318  'encoding' => 'UTF-32LE',
319  'bom' => pack('CCCC', 0xff, 0xfe, 0x00, 0x00),
320  'length' => 4,
321  ),
322  array(
323  'encoding' => 'GB-18030',
324  'bom' => pack('CCCC', 0x84, 0x31, 0x95, 0x33),
325  'length' => 4,
326  ),
327  array(
328  'encoding' => 'UTF-16BE',
329  'bom' => pack('CC', 0xfe, 0xff),
330  'length' => 2,
331  ),
332  array(
333  'encoding' => 'UTF-16LE',
334  'bom' => pack('CC', 0xff, 0xfe),
335  'length' => 2,
336  ),
337  array(
338  'encoding' => 'UTF-8',
339  'bom' => pack('CCC', 0xef, 0xbb, 0xbf),
340  'length' => 3,
341  ),
342  );
343  }

◆ getEntityComparison()

static getEntityComparison (   $xml)
staticprotected

Determine and return the string(s) to use for the <!ENTITY comparison.

Parameters
string$xml
Returns
string[]

Definition at line 189 of file Security.php.

190  {
191  $encodingMap = self::getAsciiEncodingMap();
192  return array_map(
193  array(__CLASS__, 'generateEntityComparison'),
194  self::detectXmlEncoding($xml, self::detectStringEncoding($xml))
195  );
196  }
static getAsciiEncodingMap()
Definition: Security.php:354

◆ heuristicScan()

static heuristicScan (   $xml)
staticprotected

Heuristic scan to detect entity in XML

Parameters
string$xml
Exceptions
Zend_Xml_ExceptionIf entity expansion or external entity declaration was discovered.

Definition at line 39 of file Security.php.

40  {
41  foreach (self::getEntityComparison($xml) as $compare) {
42  if (strpos($xml, $compare) !== false) {
43  throw new Zend_Xml_Exception(self::ENTITY_DETECT);
44  }
45  }
46  }

◆ isPhpFpm()

static isPhpFpm ( )
static

Return true if PHP is running with PHP-FPM

This method is mainly used to determine whether or not heuristic checks (vs libxml checks) should be made, due to threading issues in libxml; under php-fpm, threading becomes a concern.

However, PHP versions 5.5.22+ and 5.6.6+ contain a patch to the libxml support in PHP that makes the libxml checks viable; in such versions, this method will return false to enforce those checks, which are more strict and accurate than the heuristic checks.

Returns
boolean

Definition at line 167 of file Security.php.

168  {
169  $isVulnerableVersion = (
170  version_compare(PHP_VERSION, '5.5.22', 'lt')
171  || (
172  version_compare(PHP_VERSION, '5.6', 'gte')
173  && version_compare(PHP_VERSION, '5.6.6', 'lt')
174  )
175  );
176 
177  if (substr(php_sapi_name(), 0, 3) === 'fpm' && $isVulnerableVersion) {
178  return true;
179  }
180  return false;
181  }
static substr($string, $start, $end)
Definition: Security.php:379

◆ loadXmlErrorHandler()

static loadXmlErrorHandler (   $errno,
  $errstr,
  $errfile,
  $errline 
)
static
Parameters
integer$errno
string$errstr
string$errfile
integer$errline
Returns
bool

Definition at line 55 of file Security.php.

56  {
57  if (substr_count($errstr, 'DOMDocument::loadXML()') > 0) {
58  return true;
59  }
60  return false;
61  }

◆ scan()

static scan (   $xml,
DOMDocument  $dom = null 
)
static

Scan XML string for potential XXE and XEE attacks

Parameters
string$xml
DomDocument$dom
Exceptions
Zend_Xml_Exception
Returns
SimpleXMLElement|DomDocument|boolean

Definition at line 71 of file Security.php.

72  {
73  // If running with PHP-FPM we perform an heuristic scan
74  // We cannot use libxml_disable_entity_loader because of this bug
75  // @see https://bugs.php.net/bug.php?id=64938
76  if (self::isPhpFpm()) {
77  self::heuristicScan($xml);
78  }
79 
80  if (null === $dom) {
81  $simpleXml = true;
82  $dom = new DOMDocument();
83  }
84 
85  if (!self::isPhpFpm()) {
86  $loadEntities = libxml_disable_entity_loader(true);
87  $useInternalXmlErrors = libxml_use_internal_errors(true);
88  }
89 
90  // Load XML with network access disabled (LIBXML_NONET)
91  // error disabled with @ for PHP-FPM scenario
92  set_error_handler(array('Zend_Xml_Security', 'loadXmlErrorHandler'), E_WARNING);
93 
94  $result = $dom->loadXml($xml, LIBXML_NONET);
95  restore_error_handler();
96 
97  if (!$result) {
98  // Entity load to previous setting
99  if (!self::isPhpFpm()) {
100  libxml_disable_entity_loader($loadEntities);
101  libxml_use_internal_errors($useInternalXmlErrors);
102  }
103  return false;
104  }
105 
106  // Scan for potential XEE attacks using ENTITY, if not PHP-FPM
107  if (!self::isPhpFpm()) {
108  foreach ($dom->childNodes as $child) {
109  if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
110  if ($child->entities->length > 0) {
111  #require_once 'Exception.php';
112  throw new Zend_Xml_Exception(self::ENTITY_DETECT);
113  }
114  }
115  }
116  }
117 
118  // Entity load to previous setting
119  if (!self::isPhpFpm()) {
120  libxml_disable_entity_loader($loadEntities);
121  libxml_use_internal_errors($useInternalXmlErrors);
122  }
123 
124  if (isset($simpleXml)) {
125  $result = simplexml_import_dom($dom);
126  if (!$result instanceof SimpleXMLElement) {
127  return false;
128  }
129  return $result;
130  }
131  return $dom;
132  }
static heuristicScan($xml)
Definition: Security.php:39

◆ scanFile()

static scanFile (   $file,
DOMDocument  $dom = null 
)
static

Scan XML file for potential XXE/XEE attacks

Parameters
string$file
DOMDocument$dom
Exceptions
Zend_Xml_Exception
Returns
SimpleXMLElement|DomDocument

Definition at line 142 of file Security.php.

143  {
144  if (!file_exists($file)) {
145  #require_once 'Exception.php';
146  throw new Zend_Xml_Exception(
147  "The file $file specified doesn't exist"
148  );
149  }
150  return self::scan(file_get_contents($file), $dom);
151  }
static scan($xml, DOMDocument $dom=null)
Definition: Security.php:71

◆ substr()

static substr (   $string,
  $start,
  $end 
)
staticprotected

Binary-safe substr.

substr() is not binary-safe; this method loops by character to ensure multi-byte characters are aggregated correctly.

Parameters
string$string
int$start
int$end
Returns
string

Definition at line 379 of file Security.php.

380  {
381  $substr = '';
382  for ($i = $start; $i < $end; $i += 1) {
383  $substr .= $string[$i];
384  }
385  return $substr;
386  }
$start
Definition: listing.phtml:18
$i
Definition: gallery.phtml:31

Field Documentation

◆ ENTITY_DETECT

const ENTITY_DETECT = 'Detected use of ENTITY in XML, disabled to prevent XXE/XEE attacks'

Definition at line 31 of file Security.php.


The documentation for this class was generated from the following file: