Added filter for xlink:href svg xss
Simply remove all such attributes
This commit is contained in:
parent
5e6092aaf8
commit
040997fdc4
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace BookStack\Util;
|
namespace BookStack\Util;
|
||||||
|
|
||||||
|
use DOMAttr;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use DOMNodeList;
|
use DOMNodeList;
|
||||||
use DOMXPath;
|
use DOMXPath;
|
||||||
|
@ -43,13 +44,14 @@ class HtmlContentFilter
|
||||||
$badIframes = $xPath->query('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]');
|
$badIframes = $xPath->query('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]');
|
||||||
static::removeNodes($badIframes);
|
static::removeNodes($badIframes);
|
||||||
|
|
||||||
|
// Remove elements with a xlink:href attribute
|
||||||
|
// Used in SVG but deprecated anyway, so we'll be a bit more heavy-handed here.
|
||||||
|
$xlinkHrefAttributes = $xPath->query('//@*[contains(name(), \'xlink:href\')]');
|
||||||
|
static::removeAttributes($xlinkHrefAttributes);
|
||||||
|
|
||||||
// Remove 'on*' attributes
|
// Remove 'on*' attributes
|
||||||
$onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
|
$onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
|
||||||
foreach ($onAttributes as $attr) {
|
static::removeAttributes($onAttributes);
|
||||||
/** @var \DOMAttr $attr */
|
|
||||||
$attrName = $attr->nodeName;
|
|
||||||
$attr->parentNode->removeAttribute($attrName);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = '';
|
$html = '';
|
||||||
$topElems = $doc->documentElement->childNodes->item(0)->childNodes;
|
$topElems = $doc->documentElement->childNodes->item(0)->childNodes;
|
||||||
|
@ -72,7 +74,7 @@ class HtmlContentFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removed all of the given DOMNodes.
|
* Remove all the given DOMNodes.
|
||||||
*/
|
*/
|
||||||
protected static function removeNodes(DOMNodeList $nodes): void
|
protected static function removeNodes(DOMNodeList $nodes): void
|
||||||
{
|
{
|
||||||
|
@ -80,4 +82,16 @@ class HtmlContentFilter
|
||||||
$node->parentNode->removeChild($node);
|
$node->parentNode->removeChild($node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all the given attribute nodes.
|
||||||
|
*/
|
||||||
|
protected static function removeAttributes(DOMNodeList $attrs): void
|
||||||
|
{
|
||||||
|
/** @var DOMAttr $attr */
|
||||||
|
foreach ($attrs as $attr) {
|
||||||
|
$attrName = $attr->nodeName;
|
||||||
|
$attr->parentNode->removeAttribute($attrName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,28 @@ class PageContentTest extends TestCase
|
||||||
$pageView->assertDontSee('abc123abc123');
|
$pageView->assertDontSee('abc123abc123');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_svg_xlink_hrefs_are_removed()
|
||||||
|
{
|
||||||
|
$checks = [
|
||||||
|
'<svg id="test" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100"><a xlink:href="javascript:alert(document.domain)"><rect x="0" y="0" width="100" height="100" /></a></svg>',
|
||||||
|
'<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><use xlink:href="data:application/xml;base64 ,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4KPGRlZnM+CjxjaXJjbGUgaWQ9InRlc3QiIHI9IjAiIGN4PSIwIiBjeT0iMCIgc3R5bGU9ImZpbGw6ICNGMDAiPgo8c2V0IGF0dHJpYnV0ZU5hbWU9ImZpbGwiIGF0dHJpYnV0ZVR5cGU9IkNTUyIgb25iZWdpbj0nYWxlcnQoZG9jdW1lbnQuZG9tYWluKScKb25lbmQ9J2FsZXJ0KCJvbmVuZCIpJyB0bz0iIzAwRiIgYmVnaW49IjBzIiBkdXI9Ijk5OXMiIC8+CjwvY2lyY2xlPgo8L2RlZnM+Cjx1c2UgeGxpbms6aHJlZj0iI3Rlc3QiLz4KPC9zdmc+#test"/></svg>'
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->asEditor();
|
||||||
|
$page = Page::query()->first();
|
||||||
|
|
||||||
|
foreach ($checks as $check) {
|
||||||
|
$page->html = $check;
|
||||||
|
$page->save();
|
||||||
|
|
||||||
|
$pageView = $this->get($page->getUrl());
|
||||||
|
$pageView->assertStatus(200);
|
||||||
|
$pageView->assertElementNotContains('.page-content', 'alert');
|
||||||
|
$pageView->assertElementNotContains('.page-content', 'xlink:href');
|
||||||
|
$pageView->assertElementNotContains('.page-content', 'application/xml');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function test_page_inline_on_attributes_show_if_configured()
|
public function test_page_inline_on_attributes_show_if_configured()
|
||||||
{
|
{
|
||||||
$this->asEditor();
|
$this->asEditor();
|
||||||
|
|
Loading…
Reference in New Issue