Skip to content

Commit 50e8501

Browse files
committed
Content Filter: Added extra object filtering
Was blocked by CSP anyway, but best to have an extra layer.
1 parent 8a221f6 commit 50e8501

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

app/Util/HtmlContentFilter.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,17 @@ protected function filterOutScriptsFromDocument(HtmlDocument $doc): void
6161
$badForms = $doc->queryXPath('//*[' . static::xpathContains('@action', 'javascript:') . '] | //*[' . static::xpathContains('@formaction', 'javascript:') . ']');
6262
static::removeNodes($badForms);
6363

64-
// Remove data or JavaScript iFrames
64+
// Remove data or JavaScript iFrames & embeds
6565
$badIframes = $doc->queryXPath('//*[' . static::xpathContains('@src', 'data:') . '] | //*[' . static::xpathContains('@src', 'javascript:') . '] | //*[@srcdoc]');
6666
static::removeNodes($badIframes);
6767

68+
// Remove data or JavaScript objects
69+
$badObjects = $doc->queryXPath('//*[' . static::xpathContains('@data', 'data:') . '] | //*[' . static::xpathContains('@data', 'javascript:') . ']');
70+
static::removeNodes($badObjects);
71+
6872
// Remove attributes, within svg children, hiding JavaScript or data uris.
6973
// A bunch of svg element and attribute combinations expose xss possibilities.
70-
// For example, SVG animate tag can exploit javascript in values.
74+
// For example, SVG animate tag can exploit JavaScript in values.
7175
$badValuesAttrs = $doc->queryXPath('//svg//@*[' . static::xpathContains('.', 'data:') . '] | //svg//@*[' . static::xpathContains('.', 'javascript:') . ']');
7276
static::removeAttributes($badValuesAttrs);
7377

tests/Entity/PageContentFilteringTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ public function test_js_and_base64_src_urls_are_removed()
6969
'<iframe srcdoc="<script>window.alert(document.cookie)</script>"></iframe>',
7070
'<iframe SRCdoc="<script>window.alert(document.cookie)</script>"></iframe>',
7171
'<IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>',
72+
'<object data="javascript:alert(document.cookie)"></object>',
73+
'<object data="JavAScRipT:alert(document.cookie)"></object>',
74+
'<object data="JavAScRipT:alert(document.cookie)"></object>',
75+
'<object SRC=" javascript: alert(document.cookie)"></object>',
76+
'<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg==" frameborder="0"></object>',
77+
'<object data="DaTa:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg==" frameborder="0"></object>',
78+
'<object data=" data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg==" frameborder="0"></object>',
79+
'<embed src="javascript:alert(document.cookie)"/>',
80+
'<embed src="JavAScRipT:alert(document.cookie)"/>',
81+
'<embed src="JavAScRipT:alert(document.cookie)"/>',
82+
'<embed SRC=" javascript: alert(document.cookie)"/>',
83+
'<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg=="/>',
84+
'<embed src="DaTa:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg=="/>',
85+
'<embed src=" data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg=="/>',
7286
];
7387

7488
$this->asEditor();
@@ -81,6 +95,8 @@ public function test_js_and_base64_src_urls_are_removed()
8195
$pageView = $this->get($page->getUrl());
8296
$pageView->assertStatus(200);
8397
$html = $this->withHtml($pageView);
98+
$html->assertElementNotContains('.page-content', '<object');
99+
$html->assertElementNotContains('.page-content', 'data=');
84100
$html->assertElementNotContains('.page-content', '<iframe>');
85101
$html->assertElementNotContains('.page-content', '<img');
86102
$html->assertElementNotContains('.page-content', '</iframe>');
@@ -425,4 +441,25 @@ public function test_allow_list_filtering_is_controlled_by_config()
425441
$resp->assertDontSee('style="position: absolute; left: 0;color:#00FFEE;"', false);
426442
$resp->assertSee('style="color:#00FFEE;"', false);
427443
}
444+
445+
public function test_allow_list_style_filtering()
446+
{
447+
$testCasesExpectedByInput = [
448+
'<div style="position:absolute;left:0;color:#00FFEE;">Hello!</div>' => '<div style="color:#00FFEE;">Hello!</div>',
449+
'<div style="background:#FF0000;left:0;color:#00FFEE;">Hello!</div>' => '<div style="background:#FF0000;color:#00FFEE;">Hello!</div>',
450+
'<div style="color:#00FFEE;">Hello!<style>testinghello!</style></div>' => '<div style="color:#00FFEE;">Hello!</div>',
451+
];
452+
453+
config()->set('app.content_filtering', 'a');
454+
$page = $this->entities->page();
455+
$this->asEditor();
456+
457+
foreach ($testCasesExpectedByInput as $input => $expected) {
458+
$page->html = $input;
459+
$page->save();
460+
$resp = $this->get($page->getUrl());
461+
462+
$resp->assertSee($expected, false);
463+
}
464+
}
428465
}

0 commit comments

Comments
 (0)