mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
commit
0c5be13267
@ -796,14 +796,10 @@ class Director implements TemplateGlobalProvider {
|
||||
* @param string $destURL - The URL to redirect to
|
||||
*/
|
||||
protected static function force_redirect($destURL) {
|
||||
$response = new SS_HTTPResponse(
|
||||
"<h1>Your browser is not accepting header redirects</h1>".
|
||||
"<p>Please <a href=\"$destURL\">click here</a>",
|
||||
301
|
||||
);
|
||||
$response = new SS_HTTPResponse();
|
||||
$response->redirect($destURL, 301);
|
||||
|
||||
HTTP::add_cache_headers($response);
|
||||
$response->addHeader('Location', $destURL);
|
||||
|
||||
// TODO: Use an exception - ATM we can be called from _config.php, before Director#handleRequest's try block
|
||||
$response->output();
|
||||
|
@ -167,15 +167,32 @@ class Convert {
|
||||
|
||||
/**
|
||||
* Converts an XML string to a PHP array
|
||||
* See http://phpsecurity.readthedocs.org/en/latest/Injection-Attacks.html#xml-external-entity-injection
|
||||
*
|
||||
* @uses recursiveXMLToArray()
|
||||
* @param string
|
||||
*
|
||||
* @param string $val
|
||||
* @param boolean $disableDoctypes Disables the use of DOCTYPE, and will trigger an error if encountered.
|
||||
* false by default.
|
||||
* @param boolean $disableExternals Disables the loading of external entities. false by default.
|
||||
* @return array
|
||||
*/
|
||||
public static function xml2array($val) {
|
||||
$xml = new SimpleXMLElement($val);
|
||||
return self::recursiveXMLToArray($xml);
|
||||
public static function xml2array($val, $disableDoctypes = false, $disableExternals = false) {
|
||||
// Check doctype
|
||||
if($disableDoctypes && preg_match('/\<\!DOCTYPE.+]\>/', $val)) {
|
||||
throw new InvalidArgumentException('XML Doctype parsing disabled');
|
||||
}
|
||||
|
||||
// Disable external entity loading
|
||||
if($disableExternals) $oldVal = libxml_disable_entity_loader($disableExternals);
|
||||
try {
|
||||
$xml = new SimpleXMLElement($val);
|
||||
$result = self::recursiveXMLToArray($xml);
|
||||
} catch(Exception $ex) {
|
||||
if($disableExternals) libxml_disable_entity_loader($oldVal);
|
||||
throw $ex;
|
||||
}
|
||||
if($disableExternals) libxml_disable_entity_loader($oldVal);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -238,4 +238,55 @@ class ConvertTest extends SapphireTest {
|
||||
Convert::raw2json($value)
|
||||
);
|
||||
}
|
||||
|
||||
public function testXML2Array() {
|
||||
// Ensure an XML file at risk of entity expansion can be avoided safely
|
||||
$inputXML = <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]>
|
||||
<results>
|
||||
<result>Now include &long; lots of times to expand the in-memory size of this XML structure</result>
|
||||
<result>&long;&long;&long;</result>
|
||||
</results>
|
||||
XML
|
||||
;
|
||||
try {
|
||||
Convert::xml2array($inputXML, true);
|
||||
} catch(Exception $ex) {}
|
||||
$this->assertTrue(
|
||||
isset($ex)
|
||||
&& $ex instanceof InvalidArgumentException
|
||||
&& $ex->getMessage() === 'XML Doctype parsing disabled'
|
||||
);
|
||||
|
||||
// Test without doctype validation
|
||||
$expected = array(
|
||||
'result' => array(
|
||||
"Now include SOME_SUPER_LONG_STRING lots of times to expand the in-memory size of this XML structure",
|
||||
array(
|
||||
'long' => array(
|
||||
array(
|
||||
'long' => 'SOME_SUPER_LONG_STRING'
|
||||
),
|
||||
array(
|
||||
'long' => 'SOME_SUPER_LONG_STRING'
|
||||
),
|
||||
array(
|
||||
'long' => 'SOME_SUPER_LONG_STRING'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$result = Convert::xml2array($inputXML, false, true);
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$result
|
||||
);
|
||||
$result = Convert::xml2array($inputXML, false, false);
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$result
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1131,8 +1131,10 @@ after')
|
||||
|
||||
public function testRewriteHashlinks() {
|
||||
$orig = Config::inst()->get('SSViewer', 'rewrite_hash_links');
|
||||
Config::inst()->update('SSViewer', 'rewrite_hash_links', true);
|
||||
|
||||
Config::inst()->update('SSViewer', 'rewrite_hash_links', true);
|
||||
|
||||
$_SERVER['REQUEST_URI'] = 'http://path/to/file?foo"onclick="alert(\'xss\')""';
|
||||
|
||||
// Emulate SSViewer::process()
|
||||
$base = Convert::raw2att($_SERVER['REQUEST_URI']);
|
||||
|
||||
@ -1143,6 +1145,8 @@ after')
|
||||
<html>
|
||||
<head><% base_tag %></head>
|
||||
<body>
|
||||
<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>
|
||||
$ExternalInsertedLink
|
||||
<a class="inline" href="#anchor">InlineLink</a>
|
||||
$InsertedLink
|
||||
<svg><use xlink:href="#sprite"></use></svg>
|
||||
@ -1151,15 +1155,24 @@ after')
|
||||
$tmpl = new SSViewer($tmplFile);
|
||||
$obj = new ViewableData();
|
||||
$obj->InsertedLink = '<a class="inserted" href="#anchor">InsertedLink</a>';
|
||||
$obj->ExternalInsertedLink = '<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>';
|
||||
$result = $tmpl->process($obj);
|
||||
$this->assertContains(
|
||||
'<a class="inserted" href="' . $base . '#anchor">InsertedLink</a>',
|
||||
$result
|
||||
);
|
||||
$this->assertContains(
|
||||
'<a class="external-inserted" href="http://google.com#anchor">ExternalInsertedLink</a>',
|
||||
$result
|
||||
);
|
||||
$this->assertContains(
|
||||
'<a class="inline" href="' . $base . '#anchor">InlineLink</a>',
|
||||
$result
|
||||
);
|
||||
$this->assertContains(
|
||||
'<a class="external-inline" href="http://google.com#anchor">ExternalInlineLink</a>',
|
||||
$result
|
||||
);
|
||||
$this->assertContains(
|
||||
'<svg><use xlink:href="#sprite"></use></svg>',
|
||||
$result,
|
||||
@ -1192,7 +1205,7 @@ after')
|
||||
$obj->InsertedLink = '<a class="inserted" href="#anchor">InsertedLink</a>';
|
||||
$result = $tmpl->process($obj);
|
||||
$this->assertContains(
|
||||
'<a class="inserted" href="<?php echo strip_tags(',
|
||||
'<a class="inserted" href="<?php echo Convert::raw2att(',
|
||||
$result
|
||||
);
|
||||
// TODO Fix inline links in PHP mode
|
||||
|
@ -4684,7 +4684,7 @@ class SSTemplateParser extends Parser implements TemplateParser {
|
||||
$text = preg_replace(
|
||||
'/(<a[^>]+href *= *)"#/i',
|
||||
'\\1"\' . (Config::inst()->get(\'SSViewer\', \'rewrite_hash_links\') ?' .
|
||||
' strip_tags( $_SERVER[\'REQUEST_URI\'] ) : "") .
|
||||
' Convert::raw2att( $_SERVER[\'REQUEST_URI\'] ) : "") .
|
||||
\'#',
|
||||
$text
|
||||
);
|
||||
|
@ -1138,7 +1138,7 @@ class SSTemplateParser extends Parser implements TemplateParser {
|
||||
$text = preg_replace(
|
||||
'/(<a[^>]+href *= *)"#/i',
|
||||
'\\1"\' . (Config::inst()->get(\'SSViewer\', \'rewrite_hash_links\') ?' .
|
||||
' strip_tags( $_SERVER[\'REQUEST_URI\'] ) : "") .
|
||||
' Convert::raw2att( $_SERVER[\'REQUEST_URI\'] ) : "") .
|
||||
\'#',
|
||||
$text
|
||||
);
|
||||
|
@ -1109,9 +1109,9 @@ class SSViewer implements Flushable {
|
||||
if($this->rewriteHashlinks && $rewrite) {
|
||||
if(strpos($output, '<base') !== false) {
|
||||
if($rewrite === 'php') {
|
||||
$thisURLRelativeToBase = "<?php echo strip_tags(\$_SERVER['REQUEST_URI']); ?>";
|
||||
$thisURLRelativeToBase = "<?php echo Convert::raw2att(\$_SERVER['REQUEST_URI']); ?>";
|
||||
} else {
|
||||
$thisURLRelativeToBase = strip_tags($_SERVER['REQUEST_URI']);
|
||||
$thisURLRelativeToBase = Convert::raw2att($_SERVER['REQUEST_URI']);
|
||||
}
|
||||
|
||||
$output = preg_replace('/(<a[^>]+href *= *)"#/i', '\\1"' . $thisURLRelativeToBase . '#', $output);
|
||||
|
Loading…
Reference in New Issue
Block a user