我认为使用React的dangerouslySetInnerHTML
属性将从服务器获取的标记放置在页面上是非常常见的,即
const SomeComponent = () => {
const [markup, setMarkup] = useState(null)
useEffect(() => {
const resp = await fetch(...)
setMarkup(resp.content)
})
return <div dangerouslySetInnerHTML={{ __hmtl: markup }} />
}
如果这是另一种情况,并且标记来自页面上的表单,这显然会带来风险,因为您无法信任表单上输入的数据,而且我们在这里没有进行任何清理。
然而,我们将从服务器返回的数据放在页面上,因此可能存在一定程度的信任。对服务器的调用发生在代码中,并且我们可能知道正在调用的API。
但是,即使我们信任服务器,也认为来自可信服务器的数据实际上是不明智的吗?在数据返回之前,一个糟糕的参与者能干预电线吗?
完全信任dangerouslySetInnerHTML
的问题
有许多原因需要对dangerouslySetInnerHTML
采取最低限度的预防措施。由于浏览器的逻辑是在其他地方定义的,因此其他地方就会成为故障点。
- 审查和修改HTML代码逻辑构建方式的内部过程失败了吗?这是否允许XSS攻击
- 是否有人忘记续订SSL证书?域名注册?有人已经对它进行了网络订阅,现在你的应用程序使用了来自被劫持域的API
- DNS名称服务器是否被黑客入侵,将您的API域指向其他服务器?路由器或者任何中间的网络设备呢
- 你自己的服务器被黑客入侵了吗可能性最小(眨眼(,但也是可能的
安全使用dangerouslySetInnerHTML
但是,有时您需要dangerouslySetInnerHTML
,因为这是最简单的解决方案。例如,通过将标记保存和存储为原始HTML,可以非常容易地存储、保留和检索粗体、斜体等标记。
至少,在发送给用户之前,请清除任何<script>
标签的数据,以绝对消除任何有害内容的可能性。您可以使用document.createElement()
强制转换HTML,然后删除任何<script>
标记节点。
有趣的事实:SO的演示不喜欢创建带有<script>
标签的元素!下面的代码段不会运行,但它可以在JSBin.com.上运行:完整的工作演示
var el = document.createElement( 'html' );
el.innerHTML = "<p>Valid paragraph.</p><p>Another valid paragraph.</p><script>Dangerous scripting!!!</script><p>Last final paragraph.</p>";
var scripts = el.getElementsByTagName( 'script' );
for(var i = 0; i < scripts.length; i++) {
var script = scripts[i];
script.remove();
}
console.log(el.innerHTML);
document.getElementById('main').append(el);