“不会执行”的脚本是脚本标签,例如<script>
. 请参阅此处的示例:
const html = `
<script>console.log('this does NOT run');<\/script>
<img src onerror="console.log('but this will')">
`;
const App = () => {
return <div dangerouslySetInnerHTML={{__html: html}} />;
};
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class="react"></div>
如果它们附加到的事件触发,则内联处理程序(不是<script>
标签)可以运行。(上面,<img>
带有src
属性但没有有效路径的标签会抛出错误,因此它的onerror
内联处理程序会运行)
没有其他类别的脚本可以与 with 结合运行dangerouslySetInnerHTML
(除非内联处理程序本身通过其他方式注入 a <script>
,例如 with document.createElement('script')
)。
有没有办法完全阻止脚本执行,包括嵌入在我的示例中的 html 事件处理程序中的那些?
您需要删除这些on-
属性。如果删除所有on-
属性,则可能触发的任何事件都不会导致意外脚本运行。您可以先通过 DOMParser 发送输入来净化输入:
const sanitize = (input) => {
const doc = new DOMParser().parseFromString(input, 'text/html');
for (const elm of doc.querySelectorAll('*')) {
for (const attrib of elm.attributes) {
if (attrib.name.startsWith('on')) {
elm.removeAttribute(attrib.name);
}
}
}
return doc.body.innerHTML;
};
const html = `
<div>
<script>console.log('this does NOT run');<\/script>
<img src onerror="console.log('but this will')">
more content
<style type="text/css"> img {float: left; margin: 5px}</style>
</div>
`;
const App = () => {
return <div dangerouslySetInnerHTML={{__html: sanitize(html)}} />;
};
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class="react"></div>
<img src="https://www.gravatar.com/avatar/f117a950c689d3d6ec459885a908166e?s=32&d=identicon&r=PG">
如果脚本标签定义了一个函数,该函数是否仍会被加载并且以后可以调用?
不,因为<script>
标签根本不会运行,所以它内部发生的任何事情都不会做任何事情;内部定义的函数将不可见。要发生这样的事情,您必须以某种方式故意重新加载新注入的标签,使其运行。<script>