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

Sal*_*dor 7 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;
Run Code Online (Sandbox Code Playgroud)

Mas*_*ler 11

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

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

  • 关于"缓存"的评论+1,许多SQL Server可以重用sql senteces的执行计划. (6认同)
  • 这可能在MySQL中是不安全的,因为MySQL允许"逃避报价",因此QuotedStr在这里没有帮助. (3认同)

Rem*_*eau 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; 
Run Code Online (Sandbox Code Playgroud)

  • 第一段有点傻.SQL注入基本上是关于获取对数据库的未授权访问.但是,如果某人对您的应用程序本身具有调试级别访问权限,则他们不需要*SQL注入攻击来获取对数据库的访问权限; 可以假设他们已经可以访问它,与应用程序本身具有相同的权限级别. (3认同)
  • 在这种情况下,然后使用参数也是不安全的,因为用户可以更改参数的值 - 这是我在调试自己的应用程序时有时会做的事情. (2认同)
  • 即使攻击者更改参数值,使用参数仍然更安全.正如我所说,参数允许数据库引擎确保值安全且格式正确.换句话说,将不带引号的字符串传递给参数(这是您应该做的)允许引擎在执行查询时仍然正确处理字符串.这就是为什么首先使用参数来避免注入攻击的原因. (2认同)

Rob*_*edy 5

不,FormatSQL注入没有安全性.在这方面,它与普通的字符串连接没有什么不同.

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

Format在这种情况下,唯一的优点是整个字符串模板在一个地方,所以你不太可能得到间距和标点错误,如果你不得不用连续的+操作构造字符串,那么SQL撇号可以迷失在Delphi撇号中.