From db489a4adeea8edd2aab1d47b3ce55dd28198e4b Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Mon, 12 Dec 2016 19:38:34 -0800 Subject: [PATCH] Only do runtime validation of tag names when createElement is not used We introduced runtime validation of tag names because we used to generate HTML that was supposed to be inserted into a HTML string which could've been an XSS attack. However, these days we use document.createElement in most cases. That already does its internal validation in the browser which throws. We're now double validating it. Stack still has a path where innerHTML is used and we still need it there. However in Fiber we can remove it completely. --- scripts/fiber/tests-passing.txt | 2 ++ .../dom/fiber/ReactDOMFiberComponent.js | 17 ------------ .../__tests__/ReactDOMComponent-test.js | 26 ++++++++++++++----- .../dom/stack/client/ReactDOMComponent.js | 2 +- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index ed380ce55e..002f3c042f 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -664,6 +664,8 @@ src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js * should properly escape text content and attributes values * unmounts children before unsetting DOM node info * should warn about the `onScroll` issue when unsupported (IE8) +* should throw when an invalid tag name is used server-side +* should throw when an attack vector is used server-side * should throw when an invalid tag name is used * should throw when an attack vector is used * should warn about props that are no longer supported diff --git a/src/renderers/dom/fiber/ReactDOMFiberComponent.js b/src/renderers/dom/fiber/ReactDOMFiberComponent.js index 18b3341920..44afff611e 100644 --- a/src/renderers/dom/fiber/ReactDOMFiberComponent.js +++ b/src/renderers/dom/fiber/ReactDOMFiberComponent.js @@ -279,21 +279,6 @@ var voidElementTags = { ...omittedCloseTags, }; -// We accept any tag to be rendered but since this gets injected into arbitrary -// HTML, we want to make sure that it's a safe tag. -// http://www.w3.org/TR/REC-xml/#NT-Name - -var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset -var validatedTagCache = {}; -var hasOwnProperty = {}.hasOwnProperty; - -function validateDangerousTag(tag) { - if (!hasOwnProperty.call(validatedTagCache, tag)) { - invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag); - validatedTagCache[tag] = true; - } -} - function isCustomComponent(tagName, props) { return tagName.indexOf('-') >= 0 || props.is != null; } @@ -488,8 +473,6 @@ var ReactDOMFiberComponent = { rootContainerElement : Element, parentNamespace : string | null ) : Element { - validateDangerousTag(type); - // We create tags in the namespace of their parent container, except HTML // tags get no namespace. var ownerDocument = rootContainerElement.ownerDocument; diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index 0ab5a21e38..6c5661e666 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -1207,22 +1207,36 @@ describe('ReactDOMComponent', () => { }); describe('tag sanitization', () => { + it('should throw when an invalid tag name is used server-side', () => { + var hackzor = React.createElement('script tag'); + expect( + () => ReactDOMServer.renderToString(hackzor) + ).toThrowError( + 'Invalid tag: script tag' + ); + }); + + it('should throw when an attack vector is used server-side', () => { + var hackzor = React.createElement('div> ReactDOMServer.renderToString(hackzor) + ).toThrowError( + 'Invalid tag: div> { var hackzor = React.createElement('script tag'); expect( () => ReactTestUtils.renderIntoDocument(hackzor) - ).toThrowError( - 'Invalid tag: script tag' - ); + ).toThrow(); }); it('should throw when an attack vector is used', () => { var hackzor = React.createElement('div> ReactTestUtils.renderIntoDocument(hackzor) - ).toThrowError( - 'Invalid tag: div>