26

从我所看到的一切来看,在用户输入的内容上转义 html 的惯例(为了防止 XSS)似乎是在呈现内容时进行。大多数模板语言似乎默认情况下都会这样做,我遇到过类似这个 stackoverflow 的答案,他们认为这个逻辑是表示层的工作。

所以我的问题是,为什么会这样?对我来说,在输入(即表单或模型验证)时转义似乎更干净,因此您可以假设数据库中的任何内容都可以安全地显示在页面上,原因如下:

  1. 多种输出格式 - 对于现代 Web 应用程序,您可能正在使用服务器端 html 呈现、使用 AJAX/JSON 的 JavaScript Web 应用程序和接收 JSON 的移动应用程序的组合(可能有也可能没有一些 Web 视图,可能是 JavaScript 应用程序或服务器呈现的 html)。所以你必须处理到处都是 html 转义。但是输入在保存到数据库之前总是会被实例化为模型(并经过验证),并且您的模型都可以从同一个基类继承。

  2. 您已经必须小心输入以防止代码注入攻击(当然这通常被抽象为 ORM 或 db 游标,但仍然如此),所以为什么不在这里也担心 html 转义,这样您就不必担心任何事情安全相关的输出?

我很想听听为什么 html 在页面渲染上转义是首选的论点

4

2 回答 2

42

除了已经写的内容:

  • 正是因为您有多种输出格式,并且您不能保证所有这些格式都需要 HTML 转义。如果您通过 JSON API 提供数据,您不知道客户端是否需要它用于 HTML 页面或文本输出(例如电子邮件)。为什么你要强迫你的客户Jack & Jill逃避“”以获得“Jack & Jill”?

  • 默认情况下,您正在破坏您的数据。

    • 当有人对“amp”进行关键字搜索时,他们会得到“Jack & Jill”。为什么?因为你已经损坏了你的数据。

    • 假设其中一个输入是 URL http://example.com/?x=1&y=2:。您要解析此 URL,并提取y参数(如果存在)。这静默失败,因为您的 URL 已损坏为http://example.com/?x=1&y=2.

  • 这样做只是错误的层 - 与 HTML 相关的内容不应与原始 HTTP 处理混为一谈。数据库不应存储与一种可能的输出格式相关的内容。

  • XSS 和 SQL 注入不是唯一的安全问题,您处理的每个输出都存在问题 - 例如文件系统(想想像 '.php' 这样会导致 Web 服务器执行代码的扩展名)和 SMTP(想想换行符),以及任何其他人的数量。认为您可以“处理输入的安全性然后忘记它”会降低安全性。相反,您应该将转义委托给不信任其输入数据的特定后端。

  • 您不应该“到处”进行 HTML 转义。对于每个需要它的输出,您应该只执行一次- 就像对任何后端进行任何转义一样。对于 SQL,您应该进行一次SQL 转义,对于 SMTP 等也是如此。通常,您不会进行任何转义 - 您将使用一个为您处理它的库。

    如果您使用的是合理的框架/库,这并不难。我从来没有在我的网络应用程序中手动应用 SQL/SMTP/HTML 转义,也从来没有 XSS/SQL 注入漏洞。如果您构建网页的方法要求您记住应用转义,或者最终出现漏洞,那么您做错了。

  • 在表单/http 输入级别进行转义并不能确保安全,因为没有任何东西可以保证数据不会从另一条路径进入您的数据库或系统。您必须手动确保系统的所有输入都应用 HTML 转义。

    您可能会说您没有其他输入,但是如果您的系统增长了怎么办?回头改变决定通常为时已晚,因为此时您已经拥有大量数据,并且可能与外部接口兼容,例如需要担心的公共 API,这些接口都希望数据是 HTML 转义的。

  • 即使是系统的 Web 输入也不安全,因为通常您应用了另一层编码,例如您可能需要在某个入口点进行 base64 编码输入。您的自动 HTML 转义将丢失该数据中编码的任何 HTML。因此,您将不得不再次进行 HTML 转义,并记住要这样做,并跟踪您在哪里完成了它。

我在这里扩展了这些:http: //lukeplant.me.uk/blog/posts/why-escape-on-input-is-a-bad-idea/

于 2012-12-14T11:43:25.293 回答
26

最初的误解

不要混淆输出的卫生与验证。

虽然<script>alert(1);</script>是一个完全有效的用户名,但在网站上显示之前绝对必须对其进行转义。

是的,有“表示逻辑”之类的东西,它与“领域业务逻辑”无关。并且所述表示逻辑是表示层处理的内容。尤其是View实例。在编写良好的 MVC 中,视图是成熟的对象(与 RoR 试图告诉您的相反),当应用于 Web 上下文时,它会处理多个模板。

关于你的理由

不同的输出格式应该由不同的视图处理。管理 HTML、XML、JSON 和其他格式的规则和限制在每种情况下都不同。

您总是需要存储原始输入(如果您不使用准备好的语句,则进行清理以避免注入),因为有人可能需要在某些时候对其进行编辑。

存储原始版本和 xss 安全的“公共”版本是浪费。如果你想存储清理过的输出,因为每次清理它都需要太多资源,那么你已经对错误的树生气了。这是一种情况,当你使用缓存,而不是污染数据库时。

于 2012-06-28T22:24:53.837 回答