【问题标题】:Simple HTML sanitizer in JavascriptJavascript 中的简单 HTML 清理程序
【发布时间】:2010-12-10 20:55:10
【问题描述】:

我正在寻找一个用 JavaScript 编写的简单的 HTML 清理程序。它不需要 100% XSS 安全。

我正在我的网站上实现 Markdown 和 WMD Markdown 编辑器(来自 github 的 SO 主分支)。问题是实时预览中显示的 HTML 没有被过滤,就像它在 SO 上一样。我正在寻找一种用 JavaScript 编写的简单/快速的 HTML sanitizer,以便我可以过滤预览窗口的内容。

不需要具有完整 XSS 保护的完整解析器。我没有将输出发送回服务器。在将结果存储到数据库之前,我将 Markdown 发送到使用适当的完整 HTML 清理程序的服务器。

Google 对我来说完全没用。我刚刚收到数百篇(通常不正确)关于如何从用户生成的各种服务器端语言的 HTML 中过滤掉 javascript 的文章。

更新

我会更好地解释为什么我需要这个。我的网站有一个与 StackOverflow 上的非常相似的编辑器。有一个输入 MarkDown 语法的文本区域和一个预览窗口,显示提交后的样子。

当用户提交内容时,它会以 MarkDown 格式发送到服务器。服务器将其转换为 HTML,然后在其上运行 HTML sanitizer 以清理 HTML。 MarkDown 允许任意 HTML,所以我需要清理它。例如,用户键入如下内容:

<script>alert('Boo!');</script>

MarkDown 转换器不会触及它,因为它是 HTML。 HTML sanitizer 将删除它,因此脚本元素消失了。

但这不是预览窗口中发生的情况。预览窗口仅将 MarkDown 转换为 HTML,但不会对其进行清理。因此,预览窗口会有一个脚本元素。这意味着预览窗口与服务器上的实际呈现不同。

我想解决这个问题,所以我需要一个快速又脏的 JavaScript HTML sanitizer。一些简单的基本元素/属性黑名单和白名单就可以了。它不需要是 XSS 安全的,因为 XSS 保护是由服务器端 HTML sanitizer 完成的。

这只是为了确保预览窗口在 99.99% 的时间与实际渲染相匹配,这对我来说已经足够了。

你能帮忙吗?提前致谢!

【问题讨论】:

  • FWIW,当预览与发布的内容不匹配时,我讨厌它。
  • @ms2ger:这就是我需要 HTML sanitizer 的原因,以便预览与服务器在后端执行的操作相匹配。
  • 允许攻击者在您看不到他们的任何尝试的情况下在他们的浏览器中测试他们的攻击不是一个问题吗?

标签: javascript html wmd html-sanitizing


【解决方案1】:

你应该看看这个问题中推荐的Sanitize/Rewrite HTML on the Client Side

为了确保您不需要对 XSS 做更多的事情,请查看此问题的答案How to prevent Javascript injection attacks within user-generated HTML

【讨论】:

  • Caja 看起来很有用,但很重。我将不得不测试它是否足够快。不过我对此表示怀疑。我确信我不会受到 XSS 的影响,因为我正在解析的 HTML 永远不会发送到服务器。我正在发送原始的 Markdown。我需要清理的 HTML 只是预览,除了输入它的用户之外,没有人会看到它。
【解决方案2】:

我们开发了一个简单的 HtmlSantizer 并在此处开源:https://github.com/jitbit/HtmlSanitizer

用法

var result = HtmlSanitizer.SanitizeHtml(input);

[免责声明!我是作者之一!]

【讨论】:

  • thx,但是这种方法仍然会运行诸如 img onerror 之类的脚本 + 混淆此代码是否获得 GNU 或 MIT 许可(代码头与许可证文件)
  • @r3mark 修复了许可证混乱,谢谢。如果 onerror 属性没有被列入白名单,它会从 HTML 中删除,这是什么意思? (无论如何,我邀请您在 Githuib 上打开一个问题,以便我们可以正确修复它)
  • 对不起,它实际上按预期工作。我尝试清理 并且正确删除了 onerror
  • var hthl = '你好'; console.log(HtmlSanitizer.SanitizeHtml(html));该脚本还删除 tr, td
  • 在浏览了几个小时寻找一个好的解决方案之后,这正是我所需要的。迟到了,感谢@Alex。
【解决方案3】:

这是一个 2kb(取决于 Snarkdown,它是一个 1kb 的 markdown 渲染器,替换为您需要的)vue 组件,它将渲染转义的 markdown,甚至可以选择翻译 B & I 标签的内容,这些标签可能包含带有格式的标签。 ..

<template>
  <div v-html="html">
  </div>
</template>

<script>
import Snarkdown from 'snarkdown'
export default {
  props: ['code', 'bandi'],
  computed: {
    html () {
      // Convert b & i tags if flagged...
      const unsafe = this.bandi ? this.code
        .replace(/<b>/g, '**')
        .replace(/<\/b>/g, '**')
        .replace(/<i>/g, '*')
        .replace(/<\/i>/g, '*') : this.code

      // Process the markdown after we escape the html tags...
      return Snarkdown(unsafe
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#039;')
      )
    }
  }
}
</script>

作为对比,vue-markdown 超过 100kb。这不会渲染数学公式等,但 99.99% 的人不会将它用于这些事情,所以不确定为什么最流行的 markdown 组件如此臃肿:(

这对 XSS 攻击是安全的,而且速度非常快。

为什么我使用&amp;#039; 而不是&amp;apos;?因为:Why shouldn't `&apos;` be used to escape single quotes?

现在是完全不同但相关的东西......

不知道为什么还没有提到这一点...但是您的浏览器可以为您清理。

这是一个 3 行 HTML 清理程序,它可以使用浏览器附带的汇编语言版本清理速度比任何 JavaScript 变体快 30 倍……这用于 Vue/React/Angular 和许多其他 UI 框架。 请注意,这不会转义 HTML,它会删除它。

const decoder = document.createElement('div')
decoder.innerHTML = YourXSSAttackHere
const sanitized = decoder.textContent

为了证明这种方法被接受并且速度很快,这里是 Vue.js 中使用的解码器的实时链接,它使用相同的模式:https://github.com/vuejs/vue/blob/dev/src/compiler/parser/entity-decoder.js

【讨论】:

  • 问题是关于html SANITIZING,而不是REMOVING
  • 呃...我不仅在谈论清理,实际上我还提供了所提到的确切用例的示例......为降价清理,我在
  • 我没有否决您的回答。但我要指出,“清理”是指“仅删除不需要的标签/属性,保持其他所有内容完好无损”,这与“编码”或“清理”完全不同。您示例中的 textContent 属性会删除所有 HTML 标记并仅返回文本。
  • 这是转义,而不是清理en.wikipedia.org/wiki/HTML_sanitization 甚至 Snarkdown 主页都说“Snarkdown 不会清理 html”
  • 啊!感谢您的澄清和解释。非常感谢。
【解决方案4】:

另一个提示:截至 2021 年 5 月,Firefox 中即将推出 Sanitizer API。

// our input string to clean
const stringToClean = 'Some text <b><i>with</i></b> <blink>tags</blink>,, including a rogue script <script>alert(1)</script> def.';

const result = new Sanitizer().sanitizeToString(stringToClean);
console.log(result);
// Logs: "Some text <b><i>with</i></b>, including a rogue script def."

(MDN 示例)

见:https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API

如果其他供应商也接受此功能,它可能会帮助我们摆脱 JS-sanitizer-implementations。

【讨论】:

    猜你喜欢
    • 2014-06-03
    • 2012-01-25
    • 2012-04-18
    • 2019-11-22
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多