2

我有点不好意思地问这个问题,因为我应该知道答案。有人可以解释一下在下面的代码中是否以及如何发生注入?

<cfquery>
    select * from tableName
    where fieldName = '#value#'
</cfquery>

我特别好奇注入尝试和其他恶意输入,而不是处理“正常”用户输入的最佳实践或输入验证。我看到人们强烈主张使用 CFQueryParam,但不认为我明白这一点。如果用户输入已被验证与数据库模式的一致性(例如,数字数据库字段的输入必须是数字),使用 CFQueryParam 是否还有其他收获?什么<cfqueryparam CFSQLType = "CF_SQL_VARCHAR">'#value#'不做?

4

3 回答 3

9

更新:

虽然这回答了您的部分问题,但彼得的回答更好,因为它直接解决了您的问题“为什么使用 cfqueryparam,当 CF 通过转义单引号自动添加保护时?”。答:简而言之,因为后者并不总是有效。绑定变量。


它在文档中说“在单引号中转义字符串变量”,但是当您将评估变量用单引号括起来时,CF 是否已经“神奇地”在 CF 查询标记中执行此操作?

是的,大多数版本会自动转义单引号,作为不使用 cfqueryparam 的保护措施。但是,正如 Scott 上面提到的,最好使用 cfqueryparam(即绑定变量),因为它们确保参数不会作为 sql 命令执行正如彼得的回答所证明的那样,即使在自动转义不起作用的情况下,绑定变量也可以工作。

也就是说,sql 注入保护实际上只是使用绑定变量的副作用。使用绑定变量的主要原因是性能。绑定变量鼓励数据库重复使用查询计划,而不是在每次#parameters# 更改时创建新计划。这减少了编译时间,提高了性能。

Cfqueryparam 还有许多其他好处:

  • 提供数据类型检查(长度、值、类型……)
  • 提供简化“列表”和null值处理的属性
  • 在将任何 sql 发送到数据库之前执行数据类型检查,防止浪费的数据库调用

虽然它并不真正适用于字符串列,但 IMO 使用它的另一个重要原因是准确性。当您将带引号的字符串传递给数据库时,您依赖于隐式转换。本质上,您将其留给数据库来确定如何最好地执行比较,结果并不总是您所期望的。(日期字符串就是一个很好的例子)。您可能会以不准确的结果结束,或者有时查询速度较慢,具体取决于数据库决定执行 sql 的方式。使用 cfqueryparam 通过消除歧义来避免这些问题。

于 2013-09-13T19:30:14.580 回答
3

当您将评估变量用单引号括起来时,CF 是否已经“神奇地”在 CF 查询标记中执行此操作?

是的,它会'''您转换。

现在猜猜你从这段代码中得到了什么 SQL:

<cfset value = "\'; DROP TABLE tableName -- " />

<cfquery>
    select * from tableName
    where fieldName = '#value#'
</cfquery>


cfqueryparam 标签有效;使用查询参数解决 SQL 注入。

任何验证、清理或转义(所有独立的事物,顺便说一句)的自定义书面尝试最多只能与开发人员对代码运行所针对的数据库系统的了解一样好。

如果开发人员不知道其他转义方法,或者如果在验证/转义之间修改了值并将它们呈现到 SQL 中,或者即使代码库被移植到另一个数据库系统并且看起来没问题,那么就有可能使用自定义代码崩溃。

在安全方面,您不希望有这样的机会。所以使用cfqueryparam。

于 2013-09-14T00:19:40.073 回答
0

要回答问题的第一部分,请将#value#变量设置为以下内容:

someValue'; DELETE FROM tableName WHERE '1' = '1

将导致执行此查询:

<cfquery>
    select * from tableName
    where fieldName = 'someValue'; DELETE FROM tableName WHERE '1' = '1'
</cfquery>
于 2013-09-13T19:30:02.460 回答