fix(core): traverse and sanitize content of unsafe elements (#28804)

In the past, the sanitizer would remove unsafe elements, but still
traverse and sanitize (and potentially preserve) their content. This was
problematic in the case of `<style></style>` tags, whose content would
be converted to HTML text nodes.

In order to fix this, the sanitizer's behavior was changed in #25879 to
ignore the content of _all_ unsafe elements. While this fixed the
problem with `<style></style>` tags, it unnecessarily removed the
contents for _any_ unsafe element. This was an unneeded breaking change.

This commit partially restores the old sanitizer behavior (namely
traversing content of unsafe elements), but introduces a list of
elements whose content should not be traversed if the elements
themselves are considered unsafe. Currently, this list contains `style`,
`script` and `template`.

Related to #25879 and #26007.

Fixes #28427

PR Close #28804
This commit is contained in:
George Kalpakas
2019-02-18 18:14:34 +02:00
committed by Ben Lesh
parent dc9f0af080
commit 262ba67525
2 changed files with 48 additions and 26 deletions

View File

@ -36,8 +36,8 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer';
.toEqual('<p>Hello <br> World</p>');
});
it('supports removal of namespaced elements',
() => { expect(_sanitizeHtml(defaultDoc, 'a<my:hr/><my:div>b</my:div>c')).toEqual('a'); });
it('supports namespaced elements',
() => { expect(_sanitizeHtml(defaultDoc, 'a<my:hr/><my:div>b</my:div>c')).toEqual('abc'); });
it('supports namespaced attributes', () => {
expect(_sanitizeHtml(defaultDoc, '<a xlink:href="something">t</a>'))
@ -85,7 +85,7 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer';
.toEqual('<p alt="% &amp; &#34; !">Hello</p>'); // NB: quote encoded as ASCII &#34;.
});
describe('should strip dangerous elements and its content', () => {
describe('should strip dangerous elements (but potentially traverse their content)', () => {
const dangerousTags = [
'form',
'object',
@ -93,32 +93,40 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer';
'button',
'option',
'select',
'script',
'style',
];
for (const tag of dangerousTags) {
it(`${tag}`,
() => { expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual(''); });
it(tag,
() => { expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual('evil!'); });
}
const dangerousSelfClosingTags = [
'frameset',
'embed',
'input',
'param',
'base',
'basefont',
'param',
'embed',
'frameset',
'input',
'link',
'param',
];
for (const tag of dangerousSelfClosingTags) {
it(`${tag}`, () => {
it(tag, () => {
expect(_sanitizeHtml(defaultDoc, `before<${tag}>After`)).toEqual('beforeAfter');
});
}
it(`swallows frame entirely`, () => {
const dangerousSkipContentTags = [
'script',
'style',
'template',
];
for (const tag of dangerousSkipContentTags) {
it(tag, () => { expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual(''); });
}
it(`frame`, () => {
// `<frame>` is special, because different browsers treat it differently (e.g. remove it
// altogether). // We just verify that (one way or another), there is no `<frame>` element
// after sanitization.
expect(_sanitizeHtml(defaultDoc, `<frame>evil!</frame>`)).not.toContain('<frame>');
});
});
@ -133,6 +141,13 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer';
}
});
it('ignores content of script elements', () => {
expect(_sanitizeHtml(defaultDoc, '<script>var foo="<p>bar</p>"</script>')).toEqual('');
expect(_sanitizeHtml(defaultDoc, '<script>var foo="<p>bar</p>"</script><div>hi</div>'))
.toEqual('<div>hi</div>');
expect(_sanitizeHtml(defaultDoc, '<style>\<\!-- something--\>hi</style>')).toEqual('');
});
it('ignores content of style elements', () => {
expect(_sanitizeHtml(defaultDoc, '<style><!-- foobar --></style><div>hi</div>'))
.toEqual('<div>hi</div>');
@ -186,7 +201,7 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer';
// PlatformBrowser output
'<p><img src="x"></p>' :
// PlatformServer output
'');
'<p></p>');
});
if (browserDetection.isWebkit) {