我知道参数化SQL queries是最佳的方法来清理用户输入的时候建立的查询包含用户输入的,但我想知道什么是错误的,与采取的用户输入和逃避任何单一的报价和周围的整个弦用单一的报价。这里的代码:

sSanitizedInput = "'" & Replace(sInput, "'", "''") & "'"

任何单一的报价的用户进入替换双单一的报价,从而消除了用户能够结束,因此其他任何他们可能类型,例如分号,百分比的迹象,等等,将所有的字符串的一部分,而不是实际执行命令的一部分。我们正在使用Microsoft SQL Server2000年,为此我相信,单一的报价是唯一串的定界和唯一的方式来逃避串符,所以没有办法执行任何东西的用户类型中。

我没有看到任何方式启动一个SQL注射攻击,但我意识到,如果这是防弹的,因为它似乎对我的别人会认为它已经并且这将是常见的做法。我的问题是这个:什么是错的这个代码?有没有人知道一种方式来获得SQL注射攻击过去,这种消毒的技术?样本输入的用户利用这种技术将是非常有益的。

更新:

感谢大家对他们的答复;几乎所有的信息,我碰到的在我的研究表明了此页上的某个地方,这是一个标志的情报和技术人员的人采取有时间了他们的忙碌的日子来帮我弄这个问题。

原因我还没有接受任何答案是,我还是不知道的任何方式有效地启动一个SQL注射攻击这个代码。一些人建议,反斜杠会逃脱一个单一的报价,并保留其他结束串使其余的字符串将执行部分SQL的命令,我认识到,这种方法会工作注入到mySQL SQL数据库,但是在MS SQL2000年唯一的办法(我已经能够找到)逃出一个单一的报价是另一个单qoute;反斜杠不会这样做。除非有一种方法,以停止逃逸的单一的报价,没有任何其他用户输入将被执行,因为它都将作为一个毗连串。

我的理解是,有更好的方法来清理输入但我真的更多的兴趣,为什么方法我提供上述不会的工作。如果有人知道的任何具体的方式安装一个SQL注射攻击,对这种处理方法我将会爱它。

有帮助吗?

解决方案

首先,它只是不好的做法。输入确认总是必要的,但它也总是玄乎.
更糟糕的是,黑名单的验证总是有问题的,这是更好地明确和严格界定什么值/格式接受。诚然,这不是总是可能的,但在某种程度上必须做到的。
一些研究论文的主题上:

点是,任何的黑名单你做的(和太宽松的白名单)可以被绕过。最后一个链接到我的论文显示的情况下,即使报价逃离可能被绕过。

甚至如果这些情况不适用,它仍然是一个糟糕的想法。此外,除非你的程序是平凡小,你会需要处理与维护,并且也许一定数量的治理:你怎么确保其这样做的权利,无处不在的所有时间吗?

适当的方式做到这一点:

  • 白名单的验证:类型、长度、形式或者接受的价值观念
  • 如果您想要黑名单,去吧报价逃离是好的,但是在上下文中的其他缓解措施。
  • 使用的指令和参数的对象,preparse和验证
  • 呼吁参数化的查询只。
  • 更重要的是,使用存储程序。
  • 避免使用动态SQL,并不要使用的字符串连接建立的查询。
  • 如果使用卫生和植物检疫措施、还可以限制的权限的数据库,以执行所需的SPs,并不表访问直接。
  • 你也可以很容易地确认整个codebase只访问该数据库通过SPs...

其他提示

好的,这个回复将与问题的更新有关:

  

“如果有人知道对这种清理方法进行SQL注入攻击的任何特定方法,我很乐意看到它。”

现在,除了MySQL反斜杠转义 - 并考虑到我们实际上是在谈论MSSQL,实际上还有3种方法可以让SQL注入你的代码

  

sSanitizedInput ="'" &安培;替换(sInput,''","''")& "'"

考虑到这些并非一直都有效,并且非常依赖于您的实际代码:

  1. 二阶SQL注入 - 如果根据从数据库中转义后检索到的数据重建SQL查询,则数据将被转义为未转义的,并且可以间接注入SQL。见
  2. 字符串截断 - (有点复杂) - 场景是你有两个字段,比如用户名和密码,SQL连接它们。这两个领域(或者只是第一个领域)的长度都有一个硬性限制。例如,用户名限制为20个字符。说你有这个代码:
  3. username = left(Replace(sInput, "'", "''"), 20)
    

    然后你得到的是用户名,转义,然后修剪为20个字符。这里的问题 - 我会在第20个字符中引用我的引用(例如在19 a之后),并且你的转义引用将被修剪(在第21个字符中)。那么SQL

    sSQL = "select * from USERS where username = '" + username + "'  and password = '" + password + "'"
    

    结合上述格式错误的用户名将导致密码已经之外的引号,并且只会直接包含有效负载。
     3. Unicode走私 - 在某些情况下,可以传递看起来的高级unicode字符,如引号,但不是 - 直到它到达数据库,突然。由于它在您验证时不是引用,它将通过简单...查看我之前的回复以获取更多详细信息,并链接到原始研究。

简而言之:永远不要查询逃避自己。你一定会犯错。相反,使用参数化查询,或者如果由于某种原因无法执行此操作,请使用为您执行此操作的现有库。没有理由自己做。

在问到这个问题后我意识到这已经很久了,但是......

对'引用参数'过程发起攻击的一种方法是使用字符串截断。 根据MSDN,在SQL Server 2000 SP4(和SQL Server 2005 SP1)中,一个太长的字符串将被悄然截断。

引用字符串时,字符串的大小会增加。每个撇号都会重复。 然后,可以使用它将部分SQL推送到缓冲区之外。所以你可以有效地删除where子句的部分内容。

这可能在“用户管理”页面方案中非常有用,在这种情况下,您可以滥用“更新”语句,而不执行它应该执行的所有检查。

因此,如果您决定引用所有参数,请确保您知道字符串大小发生了什么,并确保您不会遇到截断。

我建议使用参数。总是。希望我能在数据库中强制执行。作为副作用,您更有可能获得更好的缓存命中率,因为更多的语句看起来相同。 (这在Oracle 8上确实如此)

输入卫生设施不是你想要的一半。用你的整个屁股。在文本字段上使用正则表达式。 TryCast您的数字到正确的数字类型,并报告验证错误,如果它不起作用。在输入中搜索攻击模式非常容易,例如' - 。假设用户的所有输入都是敌对的。

我在处理'高级搜索'功能时使用了这种技术,从头开始构建查询是唯一可行的答案。 (例如:允许用户根据产品属性的无限制约束搜索产品,将列及其允许值显示为GUI控件,以降低用户的学习阈值。)

本身就是安全的AFAIK。然而,正如另一位回答者指出的那样,您可能还需要处理退格转义(尽管不是在使用ADO或ADO.NET将查询传递给SQL Server时,至少不能保证所有数据库或技术)。

问题在于你必须确定哪些字符串包含用户输入(总是可能是恶意的),以及哪些字符串是有效的SQL查询。其中一个陷阱是如果您使用数据库中的值 - 这些值最初是由用户提供的吗?如果是这样,他们也必须逃脱。我的答案是在构造SQL查询时尽可能晚地尝试清理(但不会更晚!)。

但是,在大多数情况下,参数绑定是可行的方法 - 它只是更简单。

无论如何,你似乎知道这是一个坏主意。

像这样在字符串中转义引号之类的东西:\'

您的替换会导致:\''

如果反斜杠转义了第一个引号,则第二个引号结束了字符串。

简单回答:它有时会起作用,但不是所有时间都起作用。 你想在你做的一切上使用白名单验证,但我意识到这并不总是可行的,所以你不得不使用最佳猜测黑名单。同样,您希望在所有内容中使用参数化存储过程,但是再一次,这并不总是可行,因此您不得不将sp_execute与参数一起使用。

您可以提出任何可用的黑名单(以及一些白名单)。

这里有一个不错的文章: http://www.owasp.org/index。 PHP / Top_10_2007-A2

如果你需要这样做作为一个快速修复,让你有时间来实现一个真正的,做到这一点。但不要以为你是安全的。

有两种方法可以做到这一点,没有例外,可以安全地进行SQL注入;准备好的语句或参数化的存储过程。

如果您有可用的参数化查询,则应始终使用它们。所需要的只是一个查询通过网络而你的数据库存在风险。

是的,这应该可以正常工作直到有人运行 SET QUOTED_IDENTIFIER OFF 并使用双引号。

编辑:这并不像不允许恶意用户关闭带引号的标识符那么简单:

  

SQL Server Native Client ODBC驱动程序和SQL Server的SQL Server Native Client OLE DB提供程序在连接时自动将QUOTED_IDENTIFIER设置为ON。这可以在ODBC数据源,ODBC连接属性或OLE DB连接属性中配置。 对于来自DB-Library应用程序的连接,SET QUOTED_IDENTIFIER的默认值为OFF。

     

创建存储过程时,将捕获 SET QUOTED_IDENTIFIER和SET ANSI_NULLS设置,并将其用于后续调用该存储过程

     

SET QUOTED_IDENTIFIER也对应于ALTER DATABASE的QUOTED_IDENTIFER设置。

     

SET QUOTED_IDENTIFIER 在分析时设置。在分析时设置意味着如果批处理或存储过程中存在SET语句,则无论代码执行是否实际到达该点,它都会生效;并且SET语句在任何语句执行之前生效。

有很多方法可以在没有你必须知道的情况下关闭QUOTED_IDENTIFIER。不可否认 - 这不是你正在寻找的吸烟枪,但它是一个非常大的攻击面。当然,如果你也逃过双引号 - 那么我们就回到了我们开始的地方。 ;)

你的辩护将失败,如果:

  • 查询是预计数,而不是一个弦
  • 有任何其他方式来表示一个单一引号,其中包括:
    • 一个逃生顺序如\039
    • unicode character

(在后一种情况下,它会被什么东西这是仅扩大后你做你的替换)

帕特里克,你在所有输入,甚至数字输入附近添加单引号?如果你有数字输入,但没有在它周围加上单引号,那么你有曝光。

用户输入的所有卫生用品的丑陋代码是什么!然后是SQL语句的笨重的StringBuilder。准备好的语句方法可以产生更清晰的代码,SQL注入的好处是一个非常好的补充。

还有为什么重新发明轮子?

不是将单引号更改为(看起来像什么)两个单引号,为什么不将其更改为撇号,引号或完全删除它?

无论哪种方式,它都有点像kludge ...特别是当你合法地拥有可能使用单引号的东西(如名字)时......

注意:您的方法还假设在您的应用程序上工作的每个人都会记住在输入到达数据库之前清理输入,这在大多数情况下可能是不现实的。

虽然您可能会找到适用于字符串的解决方案,但对于数字谓词,您还需要确保它们只传递数字(简单检查是否可以将其解析为int / double / decimal?)。

这是一项额外的工作。

它可能会奏效,但对我来说似乎有点儿了。我建议通过对正则表达式进行测试来验证每个字符串是否有效。

是的,你可以的,如果...

在研究的主题,我认为,输入经过处理作为你的建议是安全的,但只有在这些规则:

  1. 你永远不会允许串值来自用户成为其他任何东西比字符串(即避免给配置的选择:"输入额外的SQL列名/表达在这里:").值比其他类型字符串(数字,日期,...):将它们转化为他们的母的数据类型,并提供例行的数字从每个数据类型。

    • SQL的陈述是有问题的验证
  2. 你要么使用 nvarchar/nchar 列(和前缀字符串与 N)或限值进入 varchar/char 列为ASCII characters只有(例如扔例外在创建SQL statement)

    • 这样你就可避免自动撇号转换从CHAR(700)CHAR(39)(以及或许其他类似Unicode黑客)
  3. 你总是验证价值的长度,以适应实际的列长度(扔例外,如果更长)

    • 有一个已知的缺陷在SQL Server允许绕过SQL错误扔在截位(导致沉默的截断)
  4. 你保证 SET QUOTED_IDENTIFIER 总是 ON

    • 当心,这是考虑到效果在分析时,即即使是在无法进入的章节的代码

遵守这4点,你应该是安全的。如果你违反了他们中的任何一种方式SQL注打开。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top