Safe escaping of fragments for eval()
This commit is contained in:
parent
9215c222ff
commit
195c57e1f5
@ -29,6 +29,10 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
|
|||||||
class Esi
|
class Esi
|
||||||
{
|
{
|
||||||
private $contentTypes;
|
private $contentTypes;
|
||||||
|
private $phpEscapeMap = array(
|
||||||
|
array('<?', '<%', '<s', '<S'),
|
||||||
|
array('<?php echo "<?"; ?>', '<?php echo "<%"; ?>', '<?php echo "<s"; ?>', '<?php echo "<S"; ?>'),
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@ -158,10 +162,34 @@ class Esi
|
|||||||
|
|
||||||
// we don't use a proper XML parser here as we can have ESI tags in a plain text response
|
// we don't use a proper XML parser here as we can have ESI tags in a plain text response
|
||||||
$content = $response->getContent();
|
$content = $response->getContent();
|
||||||
$content = str_replace(array('<?', '<%'), array('<?php echo "<?"; ?>', '<?php echo "<%"; ?>'), $content);
|
|
||||||
$content = preg_replace_callback('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', array($this, 'handleEsiIncludeTag'), $content);
|
|
||||||
$content = preg_replace('#<esi\:comment[^>]*(?:/|</esi\:comment)>#', '', $content);
|
|
||||||
$content = preg_replace('#<esi\:remove>.*?</esi\:remove>#', '', $content);
|
$content = preg_replace('#<esi\:remove>.*?</esi\:remove>#', '', $content);
|
||||||
|
$content = preg_replace('#<esi\:comment[^>]*(?:/|</esi\:comment)>#', '', $content);
|
||||||
|
|
||||||
|
$chunks = preg_split('#<esi\:include\s+(.*?)\s*(?:/|</esi\:include)>#', $content, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||||
|
$chunks[0] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[0]);
|
||||||
|
|
||||||
|
$i = 1;
|
||||||
|
while (isset($chunks[$i])) {
|
||||||
|
$options = array();
|
||||||
|
preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $chunks[$i], $matches, PREG_SET_ORDER);
|
||||||
|
foreach ($matches as $set) {
|
||||||
|
$options[$set[1]] = $set[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($options['src'])) {
|
||||||
|
throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$chunks[$i] = sprintf('<?php echo $this->esi->handle($this, %s, %s, %s) ?>'."\n",
|
||||||
|
var_export($options['src'], true),
|
||||||
|
var_export(isset($options['alt']) ? $options['alt'] : '', true),
|
||||||
|
isset($options['onerror']) && 'continue' == $options['onerror'] ? 'true' : 'false'
|
||||||
|
);
|
||||||
|
++$i;
|
||||||
|
$chunks[$i] = str_replace($this->phpEscapeMap[0], $this->phpEscapeMap[1], $chunks[$i]);
|
||||||
|
++$i;
|
||||||
|
}
|
||||||
|
$content = implode('', $chunks);
|
||||||
|
|
||||||
$response->setContent($content);
|
$response->setContent($content);
|
||||||
$response->headers->set('X-Body-Eval', 'ESI');
|
$response->headers->set('X-Body-Eval', 'ESI');
|
||||||
@ -214,32 +242,4 @@ class Esi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles an ESI include tag (called internally).
|
|
||||||
*
|
|
||||||
* @param array $attributes An array containing the attributes.
|
|
||||||
*
|
|
||||||
* @return string The response content for the include.
|
|
||||||
*
|
|
||||||
* @throws \RuntimeException
|
|
||||||
*/
|
|
||||||
private function handleEsiIncludeTag($attributes)
|
|
||||||
{
|
|
||||||
$options = array();
|
|
||||||
preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $attributes[1], $matches, PREG_SET_ORDER);
|
|
||||||
foreach ($matches as $set) {
|
|
||||||
$options[$set[1]] = $set[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($options['src'])) {
|
|
||||||
throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf('<?php echo $this->esi->handle($this, %s, %s, %s) ?>'."\n",
|
|
||||||
var_export($options['src'], true),
|
|
||||||
var_export(isset($options['alt']) ? $options['alt'] : '', true),
|
|
||||||
isset($options['onerror']) && 'continue' == $options['onerror'] ? 'true' : 'false'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -124,10 +124,10 @@ class EsiTest extends \PHPUnit_Framework_TestCase
|
|||||||
$esi = new Esi();
|
$esi = new Esi();
|
||||||
|
|
||||||
$request = Request::create('/');
|
$request = Request::create('/');
|
||||||
$response = new Response('foo <?php die("foo"); ?><%= "lala" %>');
|
$response = new Response('<?php <? <% <script language=php>');
|
||||||
$esi->process($request, $response);
|
$esi->process($request, $response);
|
||||||
|
|
||||||
$this->assertEquals('foo <?php echo "<?"; ?>php die("foo"); ?><?php echo "<%"; ?>= "lala" %>', $response->getContent());
|
$this->assertEquals('<?php echo "<?"; ?>php <?php echo "<?"; ?> <?php echo "<%"; ?> <?php echo "<s"; ?>cript language=php>', $response->getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user