格式函数vs sql注入方案中的参数?

时间:2012-06-20 21:05:07

标签: sql delphi sql-injection

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

喜欢这个样本

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

3 个答案:

答案 0 :(得分:11)

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

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

答案 1 :(得分:5)

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

使用实际的SQL参数是最安全的方法。它不仅可以避免注入,而且还允许SQL引擎决定如何最好地将参数格式化为自己的需要,这样您就不必担心在自己的代码中格式化值,它适用于强类型语言(如Delphi)。更不用说能够提前在服务器端准备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; 

答案 2 :(得分:5)

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

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

Format在此上下文中的唯一优势是整个字符串模板位于一个位置,因此如果必须构造字符串,则不太可能得到间距和标点符号错误连续的+操作,其中SQL撇号可能在Delphi撇号中丢失。