mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
Merge pull request #2798 from creative-commoners/pulls/4.11/cve-2022-37421
Sanitise ExtraMeta field for XSS
This commit is contained in:
commit
8526067c73
@ -69,6 +69,7 @@ use SilverStripe\Versioned\RecursivePublishable;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\HTML;
|
||||
use SilverStripe\View\Parsers\HTMLValue;
|
||||
use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
use SilverStripe\View\Parsers\URLSegmentFilter;
|
||||
use SilverStripe\View\Shortcodes\EmbedShortcodeProvider;
|
||||
@ -1684,6 +1685,8 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
|
||||
$this->setNextWriteWithoutVersion(true);
|
||||
}
|
||||
|
||||
$this->sanitiseExtraMeta();
|
||||
|
||||
// Flush cached [embed] shortcodes
|
||||
// Flush on both DRAFT and LIVE because VersionedCacheAdapter has separate caches for both
|
||||
// Clear both caches at once for the scenario where a CMS-author updates a remote resource
|
||||
@ -1703,6 +1706,27 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
|
||||
}
|
||||
}
|
||||
|
||||
private function sanitiseExtraMeta(): void
|
||||
{
|
||||
$htmlValue = HTMLValue::create($this->ExtraMeta);
|
||||
/** @var DOMElement $el */
|
||||
foreach ($htmlValue->query('//*') as $el) {
|
||||
/** @var DOMAttr $attr */
|
||||
$attributes = $el->attributes;
|
||||
for ($i = count($attributes) - 1; $i >= 0; $i--) {
|
||||
$attr = $attributes->item($i);
|
||||
// remove any attribute starting with 'on' e.g. onclick
|
||||
// and remove the accesskey attribute
|
||||
if (substr($attr->name, 0, 2) === 'on' ||
|
||||
$attr->name === 'accesskey'
|
||||
) {
|
||||
$el->removeAttributeNode($attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->ExtraMeta = $htmlValue->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger synchronisation of link tracking
|
||||
*
|
||||
@ -1797,6 +1821,16 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure ExtraMeta can be turned into valid HTML
|
||||
if ($this->ExtraMeta && !HTMLValue::create($this->ExtraMeta)->getContent()) {
|
||||
$result->addError(
|
||||
_t(
|
||||
'SilverStripe\\CMS\\Model\\SiteTree.InvalidExtraMeta',
|
||||
'Custom Meta Tags does not contain valid HTML',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -208,6 +208,7 @@ en:
|
||||
HTMLEDITORTITLE: Content
|
||||
INHERIT: 'Inherit from parent page'
|
||||
INHERITSITECONFIG: 'Inherit from site access settings'
|
||||
InvalidExtraMeta: 'Custom Meta Tags does not contain valid HTML'
|
||||
LASTPUBLISHED: 'Last published'
|
||||
LASTSAVED: 'Last saved'
|
||||
LASTUPDATED: 'Last Updated'
|
||||
|
@ -1986,4 +1986,51 @@ class SiteTreeTest extends SapphireTest
|
||||
);
|
||||
// END ARCHIVED
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideSanitiseExtraMeta
|
||||
*/
|
||||
public function testSanitiseExtraMeta(string $extraMeta, string $expected, string $message): void
|
||||
{
|
||||
$siteTree = new SiteTree();
|
||||
$siteTree->ExtraMeta = $extraMeta;
|
||||
$siteTree->write();
|
||||
$this->assertSame($expected, $siteTree->ExtraMeta, $message);
|
||||
}
|
||||
|
||||
public function provideSanitiseExtraMeta(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'<link rel="canonical" accesskey="X" sometrigger="alert(1)" />',
|
||||
'<link rel="canonical" sometrigger="alert(1)">',
|
||||
'accesskey attribute is removed'
|
||||
],
|
||||
[
|
||||
'<link rel="canonical" onclick="alert(1)" /><meta name="x" onerror="alert(0)">',
|
||||
'<link rel="canonical"><meta name="x">',
|
||||
'Attributes starting with "on" are removed'
|
||||
],
|
||||
[
|
||||
'<link rel="canonical" onclick=alert(1) /><meta name="x" onerror=\'alert(0)\'>',
|
||||
'<link rel="canonical"><meta name="x">',
|
||||
'Attributes with different quote styles are removed'
|
||||
],
|
||||
[
|
||||
'<link rel="canonical" ONCLICK=alert(1) /><meta name="x" oNeRrOr=\'alert(0)\'>',
|
||||
'<link rel="canonical"><meta name="x">',
|
||||
'Mixed case attributes are removed'
|
||||
],
|
||||
[
|
||||
'<link rel="canonical" accesskey="X" onclick="alert(1)" name="x" />',
|
||||
'<link rel="canonical" name="x">',
|
||||
'Multiple attributes are removed'
|
||||
],
|
||||
[
|
||||
'<link rel="canonical" href="valid" ;;// somethingdodgy < onmouseover=alert(1)',
|
||||
'<link rel="canonical" href="valid" somethingdodgy="">',
|
||||
'Invalid HTML is converted to valid HTML and parsed'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user