何时过滤/清理数据:在数据库插入之前还是在显示之前?

25

当我准备解决输入数据过滤和净化的问题时,我想知道是否有最佳实践(或最常用的实践)?在将数据(包括HTML、JavaScript等)插入数据库之前进行过滤/净化,还是在准备在HTML中显示数据时进行处理更好?

一些注意事项:

  • 我使用PHP进行此操作,但我认为答案与编程语言无关。但如果您对PHP有任何建议,请分享!
  • 这不是转义数据以用于数据库插入的问题。我的PDO已经很好地处理了这个问题。

谢谢!


1
请查看我对以下问题的回答:https://dev59.com/8HVC5IYBdhLWcg3w-WSs#130323 - troelskn
6个回答

21

在显示用户提交数据时,普遍认为的信条是"过滤输入,转义输出"。

我建议不要在将数据存入数据库之前转义像html实体等内容,因为您永远不知道HTML何时不再是您的展示媒介。此外,不同类型的情况需要不同类型的输出转义。例如,在Javascript中嵌入字符串需要不同于在HTML中的转义。在此之前这样做可能会使您产生错误的安全感。

因此,基本的原则是,在使用之前对其进行净化,并具体针对该用途;而不是预先处理。

(请注意,我不是在谈论SQL输出转义,而是仅针对显示。但仍然请转义绑定到SQL字符串的数据)。


总体来说,这是一个非常好的提示,特别是“我建议不要在进入数据库之前转义诸如HTML实体等内容,因为您永远不知道HTML何时不会成为您的显示媒介”。 - Jeach

12

我希望保留数据的原始形式。

只有在使用数据的特定场合下,我才会进行转义/过滤。

  • 在网页上 - 对所有HTML编码
  • 在SQL中 - 去除引号
  • 在URL中 - 进行URL编码
  • 在打印机上 - 对转义命令进行编码
  • 在其他情况下 - 根据具体工作进行编码

8

至少有两种过滤/净化类型需要注意:

  • SQL
  • HTML

显然,第一个必须在将数据插入数据库之前/之时处理,以防止SQL注入。但是您已经知道了这一点,因此我不会再多说了。


另一方面,第二个问题更有趣:

  • 如果您的用户必须能够编辑其数据,则将其以与最初输入的方式返回给他们非常有趣;这意味着您必须存储“未转义html特殊字符”的版本。
  • 如果您想显示某些HTML,则可能会使用类似HTMLPurifier的工具:非常强大...但是如果每次显示数据时都要运行它,则可能需要太多资源...

所以:

  • 如果要显示一些HTML,并使用重型工具来验证/过滤它,我建议您需要将已过滤/其他版本存储到数据库中,以免破坏服务器并重新创建它每次显示数据时。
    • 但是您还需要存储“原始”版本(请参见我之前说的)
    • 在这种情况下,即使需要更多空间,我也可能会将两个版本都存储到数据库中...或者至少使用一些良好的缓存机制,以不要反复创建干净的版本。
  • 如果不想显示任何HTML,则将使用htmlspecialchars或等效项,这可能并不会占用太多CPU...因此可能并不重要
    • 您仍然需要存储“原始”版本
    • 但是在输出数据时进行转义可能没问题。

顺便说一句,如果用户在输入数据时使用类似于bbcode/markdown/wiki的东西,并且您正在将其呈现为HTML,则第一种解决方案也很好...
至少,在它被更新之前经常显示它--尤其是如果您不使用任何缓存来存储干净的HTML版本。


(关于特定的HTML清理)八年后,现在客户端渲染如此普遍,“我会说你需要将已经过滤/处理过的版本存储到数据库中,以免破坏服务器”的观点现在更加相关。清理HTML是一项昂贵的操作,在许多情况下,对保存进行清理而不是在显示时进行清理会更有意义。在这里存在明显的权衡取舍,因为该操作是有损的,并且需要数据迁移来更新清理规则,但在许多情况下,这些权衡是非常值得的。 - Ben Regenspan

6

如果需要,在将其放入数据库之前,为数据库清理数据(即如果您未使用处理此操作的数据库互动层)。在显示之前,为显示清理数据。

以目前不必要的引用形式存储东西只会导致太多问题。


6
我总是建议在将内容传递到需要转义的地方之前立即进行转义。您的数据库不关心HTML,因此在存储到数据库之前转义HTML是不必要的。如果您想要输出其他格式的内容,或更改允许/禁止使用的标签,则可能需要做一些工作。此外,在需要转义时正确执行转义比在处理过程的早期阶段记住要做转义要容易得多。
另外值得注意的是,HTML转义的字符串可能比原始输入长得多。如果我在注册表单中输入一个日语用户名,原始字符串可能只有4个Unicode字符,但是HTML转义可能会将其转换为一长串“〹𐤲䡈穩”。然后我的4个字符的用户名对于您的数据库字段来说太长了,并且会被存储为两个日语字符加上半个转义代码,这也可能会阻止我登录。
请注意,浏览器倾向于自行转义某些内容,例如提交的表单中的非英文文本,而且总会有那些聪明的人在所有地方使用日语用户名。因此,您可能需要在存储之前实际上取消转义 HTML。

4
大多数情况下,这取决于您计划如何使用输入以及您的开发环境。
在大多数情况下,您需要原始输入。这样,您就可以随心所欲地调整输出,而不必担心失去原始数据。这也使您能够解决诸如损坏的输出之类的问题。您始终可以看到您的过滤器存在漏洞或客户输入有误。
另一方面,某些短语义数据可能需要立即过滤。1)您不希望数据库中有混乱的电话号码,因此对于此类事情进行消毒可能是有益的。2)您不希望其他程序员意外输出未经转义的数据,并且您在多程序员环境中工作。然而,在大多数情况下,我认为原始数据更好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接