清理参数化查询的输入

信息安全 sql注入 mysql sql服务器
2021-09-03 16:09:36

如果我在任何地方都使用完全参数化的查询,是否仍然有必要和/或安全相关以某种方式清理输入?例如,在向数据库发送参数化查询之前检查邮件地址是否有效,或者从文本中过滤掉某些特殊字符?

我想到了良性但设计不那么好的第 3 方工具(可能是管理员自己编写的脚本,或者是非技术人员制作的一些花哨的 CrystalReports)试图从我们的数据库中使用未经清理的数据。

现在,我们对 SQL Server 有完整的 unicode 支持(MySQL 似乎有 Emojis 的问题),我不确定如何在不丢失该属性的情况下过滤安全风险。

3个回答

不,这是没有必要的。但是,请继续阅读。

输入清理是一个可怕的术语,它假装您可以对数据挥动魔杖并使其成为“安全数据”。问题在于,当数据被不同的软件解释时,“安全”的定义会发生变化。

可以安全地嵌入到 SQL 查询中的数据可能不安全地嵌入到 HTML 中。或 JSON。或外壳命令。或 CSV。并且剥离(或彻底拒绝)值以便它们可以安全地嵌入所有这些上下文(以及许多其他上下文)中,限制性太强。

那么我们应该怎么做呢?确保数据永远不会造成损害。

实现这一点的最佳方法是首先避免解释数据。参数化 SQL 查询就是一个很好的例子;参数永远不会被解释为 SQL,它们只是作为数据放入数据库中。

对于许多其他情况,数据仍然需要以其他格式嵌入,例如 HTML。在这种情况下,该特定语言的数据应在嵌入时进行转义。因此,为了防止 XSS,数据在查看时进行了 HTML 转义。不是在输入时。这同样适用于其他嵌入情况。

那么,我们应该直接将我们得到的任何东西传递给数据库吗?

或许。这取决于。

您肯定可以检查有关用户输入的一些事情,但这高度依赖于上下文。因为 sanitization 定义不明确且被误用,所以我更喜欢称它为validation

  • 例如,如果某个字段应该是整数,您当然可以验证该字段以确保它包含整数(或者可能为 NULL)。
  • 您当然可以对电子邮件字段进行一些验证(尽管有些人认为除了检查 a 的存在之外您无能为力@,他们有一个很好的观点)。
  • 您可以要求评论具有最小和最大长度。
  • 您可能应该验证任何字符串仅包含对其编码的有效字符(例如,没有无效的 UTF-8 序列)。
  • 如果这对您的用户群有意义,您可以将用户名限制为某些字符。
  • 当然,密码的最小长度非常普遍。

如您所见,这些检查非常依赖于上下文。所有这些都是为了帮助增加您最终获得有意义数据的几率。它们不是为了保护您的应用程序免受恶意输入(SQL 注入、XSS、命令注入等),因为这不是这样做的地方。

用户应该可以自由打字'; DROP TABLE users; --,而他们的帖子不会被拒绝或修改为\'; DROP TABLE users; --. 请注意,我可以在 sec.SE 上包含此类“恶意”内容!

所以,回答你原来的问题:

...以某种方式清理输入是否仍然有必要和/或与安全相关?

不它不是。但是请在输出之前正确地转义需要的数据。并在适用的情况下考虑验证。

我想到了良性但设计不那么好的第 3 方工具(可能是管理员自己编写的脚本,或者是非技术人员制作的一些花哨的 CrystalReports)试图从我们的数据库中使用未经清理的数据。

然后在输出到这些工具之前转义或过滤数据,但不要破坏数据库中的数据。

但实际上,这些脚本应该被修复,或者考虑到安全性而重写。

(MySQL似乎对Emojis有问题)

有点离题,但看看utfmb4MySQL字符集;)

如果我在任何地方都使用完全参数化的查询,是否仍然有必要和/或安全相关以某种方式清理输入?

是的。在将输入发送到数据库之前对其进行清理总是一个好主意。

参数化查询可能会使您免受 SQL 注入攻击,但在存储型 XSS 攻击的情况下可能无益。如果用户将恶意 javascript 代码发送到您的表单中,并且您将其成功存储在数据库中,并且您在其他地方显示相同的字段,则恶意脚本可能会在受害者的浏览器上运行。

在发送之前清理输入总是一个好主意,并在将输出发送到客户端浏览器之前清理输出。

编辑:正如评论中所指出的,清理与编码/转义值不同。在这里,清理意味着可以在将输入传递到数据库(或任何其他层)之前验证输入以进行一些基本检查。例如,可以验证需要电子邮件地址的字段是否为有效电子邮件地址,可以仅验证年龄字段是否为整数,等等。正则表达式证明在这里有很大的帮助。应该注意的是,这些检查应该放在前端(客户端)以及后端。

对于需要富文本的字段,您可以在将显示用户输入的页面上实施内容安全策略。您还可以使用 HTML sanitizer 来清理用户输入。

是的,您应该始终清理输入数据。卫生不仅仅是保护您免受注入,还可以验证类型、限制值(枚举)、范围等。虽然攻击者可能无法操纵您的 sql,但它们仍然可能在其余部分中导致不良行为你的申请。

例如,如果攻击者更改了枚举值,他们可以操纵系统吗?他们是否只是更改了角色、用户类型等...?或者,他们可以输入一个大于您的架构或数据类型(字节 v int32、int64)可接受的值,这可能会导致应用程序崩溃,从而暴露信息或使孤立数据发生更改(未处理)。