7

我知道sql语句中参数的使用,但是出于好奇,使用Format函数来防止sql注入而不是使用参数是安全的。

喜欢这个样本

sCustomer : string
begin
 AdoSql.CommandText:=Format('Select SUM(value) result from invoices where customer=%s',[QuotedStr(sCustomer)]);
end;
4

3 回答 3

11

假设按预期工作并且没有可以破坏它的边缘情况,这可能对 SQL 注入是安全的。QuotedStr(这绝不是保证。正如 Linas 在评论中指出的那样,MySql 允许您使用\'转义引号。其他 DBMS 可能具有类似的功能。具有足够系统理论知识的攻击者将能够利用它们。)

但是,即使 QuotedStr 足够好,出于不同的原因使用参数仍然更好:性能。当您将参数与查询分开时,您最终可能会使用不同的参数多次发送完全相同的查询代码。如果这样做,数据库可以缓存它在计算查询时所做的大量工作,因此您的数据库访问速度会更快。当您将参数混合到查询代码本身时,这不起作用(或至少不起作用)。

于 2012-06-20T21:14:54.963 回答
6

每当您通过将字符串连接在一起来构建 SQL 字符串时,都存在注入攻击的可能性,无论您认为访问这些字符串有多安全。如您所知,有人可以在调试器中运行您的应用程序,在结果上设置断点,并在允许查看QuotedStr()之前修改其内容。Format()

使用实际的 SQL 参数是最安全的方法。它不仅避免了注入,而且还允许 SQL 引擎根据自己的需要决定如何最好地格式化参数,因此您不必担心在自己的代码中格式化值,它适用于强类型语言(如德尔福)。更不用说能够提前在服务器端准备 SQL 语句然后在代码中执行它的性能优势,甚至多次,大大减少了客户端和服务器之间的流量并提高了整体性能。

var
  sCustomer : string 
begin 
  AdoSql.CommandText := 'Select SUM(value) result from invoices where customer=:Customer'; 
  AdoSql.Prepared := True;
  ... 
  AdoSql.Parameters['Customer'].Value := sCustomer; 
  AdoSql1.ExecSQL;
  ...
  AdoSql.Parameters['Customer'].Value := sCustomer;
  AdoSql1.ExecSQL;
  ...
  AdoSql.Prepared := False;
end; 
于 2012-06-20T22:11:56.633 回答
5

不,Format不提供 SQL 注入的安全性。在这方面,它与普通的字符串连接没有什么不同。

问题中对 SQL 注入执行任何操作的代码部分是调用QuotedStr,您可以使用或不使用Format。但是,它不像真正的参数化查询那样可靠。

在这种情况下,唯一的优点Format是整个字符串模板都在一个位置,因此与必须通过连续操作构造字符串相比,您不太可能出现空格和标点错误+,而 SQL 撇号可以迷失在德尔福撇号之间。

于 2012-06-21T04:04:13.180 回答