使用 dangerouslySetInnerHTML 执行脚本
Script execution with dangerouslySetInnerHTML
我在几个地方读到,当我们使用 React dangerouslySetInnerHTML
插入一个 html 片段时,脚本没有被执行。
但是我只是想插入这个:
<img src= "img.png" onload="alert('picture loaded')" alt="script test">
并触发了警报。
这并没有让我感到惊讶(这就是我首先进行测试的原因),但我想更好地理解“脚本不执行”的含义。
我的问题:
- 除了我上面的例子,还有其他类型的脚本
会执行吗?
- 有没有办法完全阻止脚本执行,
包括像我的示例中那样嵌入 html 事件处理程序的那些?
- 如果脚本标签定义了一个函数,该函数是否仍然是
已加载并稍后可调用?
- 我应该注意的任何其他行为?
[编辑] 我在函数组件中使用 dangerouslySetInnerHTML
:
const htmlString = '<img src="img.png" onload="alert('picture loaded')" alt="script test">'
在return语句中(JSX):
return <div dangerouslySetInnerHTML={{__html: htmlString}} />
“不会执行”的脚本是脚本 tags,例如 <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>
标记,可以 运行,如果它们附加到触发事件。 (上面,带有 src
属性 但没有有效路径的 <img>
标记会引发错误,因此它的 onerror
内联处理程序 运行s)
没有其他类别的脚本可以 运行 与 dangerouslySetInnerHTML
结合使用(除非内联处理程序本身通过其他方式注入 <script>
,例如 document.createElement('script')
).
is there a way to fully prevent script execution, including those embedded in html event handlers like in my example?
您需要删除 on-
属性。如果删除所有 on-
属性,则可能触发的任何事件都不会导致意外脚本 运行ning。您可以先通过 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">
if a script tag defines a function, will that function still be loaded and be callable later?
不,因为 <script>
标签根本没有 运行,所以里面发生的任何事情都不起作用;内部定义的函数将不可见。要发生这种情况,您必须以某种方式 deliberately reload 新注入的 <script>
标记,使其到达 运行.
我在几个地方读到,当我们使用 React dangerouslySetInnerHTML
插入一个 html 片段时,脚本没有被执行。
但是我只是想插入这个:
<img src= "img.png" onload="alert('picture loaded')" alt="script test">
并触发了警报。
这并没有让我感到惊讶(这就是我首先进行测试的原因),但我想更好地理解“脚本不执行”的含义。
我的问题:
- 除了我上面的例子,还有其他类型的脚本 会执行吗?
- 有没有办法完全阻止脚本执行, 包括像我的示例中那样嵌入 html 事件处理程序的那些?
- 如果脚本标签定义了一个函数,该函数是否仍然是 已加载并稍后可调用?
- 我应该注意的任何其他行为?
[编辑] 我在函数组件中使用 dangerouslySetInnerHTML
:
const htmlString = '<img src="img.png" onload="alert('picture loaded')" alt="script test">'
在return语句中(JSX):
return <div dangerouslySetInnerHTML={{__html: htmlString}} />
“不会执行”的脚本是脚本 tags,例如 <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>
标记,可以 运行,如果它们附加到触发事件。 (上面,带有 src
属性 但没有有效路径的 <img>
标记会引发错误,因此它的 onerror
内联处理程序 运行s)
没有其他类别的脚本可以 运行 与 dangerouslySetInnerHTML
结合使用(除非内联处理程序本身通过其他方式注入 <script>
,例如 document.createElement('script')
).
is there a way to fully prevent script execution, including those embedded in html event handlers like in my example?
您需要删除 on-
属性。如果删除所有 on-
属性,则可能触发的任何事件都不会导致意外脚本 运行ning。您可以先通过 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">
if a script tag defines a function, will that function still be loaded and be callable later?
不,因为 <script>
标签根本没有 运行,所以里面发生的任何事情都不起作用;内部定义的函数将不可见。要发生这种情况,您必须以某种方式 deliberately reload 新注入的 <script>
标记,使其到达 运行.