|
1 | 1 | 'use strict'
|
2 | 2 | import PropTypes from 'prop-types'
|
3 | 3 | import React, { PureComponent } from 'react'
|
4 |
| -import serialize from 'serialize-javascript' |
| 4 | +import DOMPurify from 'dompurify' |
5 | 5 |
|
6 | 6 | // @twreporter
|
7 | 7 | import webfonts from '@twreporter/react-components/lib/text/utils/webfonts'
|
@@ -110,17 +110,41 @@ export default class Html extends PureComponent {
|
110 | 110 | {styleElement}
|
111 | 111 | </head>
|
112 | 112 | <body>
|
113 |
| - <div id="root" dangerouslySetInnerHTML={{ __html: contentMarkup }} /> |
| 113 | + <div id="root" |
| 114 | + dangerouslySetInnerHTML={{ |
| 115 | + __html: DOMPurify.sanitize(contentMarkup, { |
| 116 | + FORBID_SCRIPTS: true, // Completely forbid scripts in content |
| 117 | + FORBID_EVAL: true, |
| 118 | + FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input'], |
| 119 | + ADD_ATTR: ['target'], |
| 120 | + ALLOWED_TAGS: [ |
| 121 | + // Content tags only - no script tags |
| 122 | + 'div', 'p', 'span', 'a', 'img', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', |
| 123 | + 'ul', 'ol', 'li', 'br', 'strong', 'em', 'blockquote', 'figure', 'figcaption', |
| 124 | + 'table', 'thead', 'tbody', 'tr', 'th', 'td' |
| 125 | + ], |
| 126 | + ALLOWED_ATTR: [ |
| 127 | + 'href', 'src', 'alt', 'title', 'class', 'id', 'target' |
| 128 | + ], |
| 129 | + CUSTOM_ELEMENT_HANDLING: { |
| 130 | + tagNameCheck: /^[a-zA-Z\-]+$/, |
| 131 | + attributeNameCheck: /^[a-zA-Z\-]+$/, |
| 132 | + allowCustomizedBuiltInElements: false |
| 133 | + }, |
| 134 | + RETURN_DOM_FRAGMENT: false, |
| 135 | + RETURN_DOM: false |
| 136 | + }) |
| 137 | + }} |
| 138 | + /> |
114 | 139 | <script
|
115 | 140 | defer
|
116 | 141 | src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Intl.~locale.zh-Hant-TW"
|
117 | 142 | />
|
118 | 143 | <script
|
119 |
| - dangerouslySetInnerHTML={{ |
120 |
| - __html: `window.__REDUX_STATE__=${serialize(store.getState())};`, |
121 |
| - }} |
122 | 144 | charSet="UTF-8"
|
123 |
| - /> |
| 145 | + > |
| 146 | + {`window.__REDUX_STATE__ = ${JSON.stringify(store.getState())};`} |
| 147 | + </script> |
124 | 148 | {_.map(scripts, (script, key) => (
|
125 | 149 | <script src={script} key={'scripts' + key} charSet="UTF-8" />
|
126 | 150 | ))}
|
|
0 commit comments