SQL注入攻击似乎有些歇斯底里.最近,在这里
如何根据另一个字段中的查找值返回一个字段中的值
如果我在Excel中创建一个连接到Access数据库的宏,我真的必须关注SQL注入吗?它不在网上,它在我的办公室使用(你们还记得台式机吗?).我并不担心我的同事会破坏我.如果他们足够聪明,可以进行SQL注入,他们是否足够聪明,无法破解我的加载密码并只是更改代码?
如果你在宏中构建SQL,它很容易受到SQL注入的攻击.即使你相信那些将使用这个东西的人,你至少应该注意基础知识,就像人们试图将单引号和分号字符放入数据库字段一样.在您的情况下,这不仅仅是数据验证的安全问题.
SQL注入不仅仅是一种安全威胁,它也是一个非常真实的漏洞来源.
你确定你的记录中都没有一个撇号(')吗?
INSERT INTO NAMES (FIRSTNAME, LASTNAME) VALUES('Jack', 'O'Neill')
在这种情况下,即使没有人想破解您的系统,您也有一个错误.
你永远不知道什么时候鲍比表会使用你的单词宏:
我想扩展我上面的评论,以回应onedaywhen的帖子,概述如何在MS Access中利用SELECT语句.请记住,这些不是关于如何防止SQL注入的一般性注释,而是专门应用于MS Access中的编程.
我从来没有见过任何用于Access的示例代码,它允许在概述时使用SELECT的那种漏洞.这样做的原因是,几乎从来没有这样的情况,你会使用这种简单的方法收集标准,而不是在整个过程中对输入进行一些验证,不是为了避免SQL注入,而是为了避免由无效的SQL引起的错误.
这是实现最简单版本的代码:
Public Sub TestSQLExploit() Dim strSQL As String strSQL = "SELECT tblInventory.* FROM tblInventory WHERE InventoryID = " strSQL = strSQL & InputBox("Enter InventoryID") Debug.Print strSQL End Sub
所以,传递"10036或'a'='a'"产生这个SQL:
SELECT tblInventory.* FROM tblInventory WHERE InventoryID=10036 Or 'a'='a'
这绝对不是好事!
现在,我永远不会以这种方式编写代码,因为我总是希望允许多个值.相反,如果我使用InputBox()函数来收集用户输入(我真的从来没有这样做,因为它太难以验证),我会使用Application.BuildCriteria来编写WHERE子句,因为这样我就可以处理多个标准值.这将导致此代码:
Public Sub TestSQLExploit1() Dim strSQL As String Dim strWhere As String strSQL = "SELECT tblInventory.* FROM tblInventory " strWhere = "WHERE " & Application.BuildCriteria("tblInventory.InventoryID", _ dbLong, InputBox("Enter InventoryID")) strSQL = strSQL & strWhere Debug.Print strSQL End Sub
老实说,我认为Application.BuildCriteria会对此产生错误,但它没有,并且当传递"10036或'a'='a'"产生完全相同的SQL时.正如你所说的那样,由于Jet表达式服务的工作方式,它将是敞开的.
现在,我从来没有真正写过像这样的动态SQL,因为我只是不喜欢InputBox()函数,正是因为你必须编写一堆代码来验证输入.如果你像上面的代码一样使用它,你必须做很多事情以确保它是有效的.
我从未见过这种操作的任何访问代码示例,不建议使用参数化SQL(当然,这将避免问题)或Query-By-Form接口.我通常不在Access中使用保存的参数查询,因为我喜欢编写我保存的查询以便在任何地方都可用.这意味着它们通常没有WHERE子句,这些子句具有在运行时更改的条件.当我使用这些保存的查询时,我提供适当情况的WHERE子句,无论是作为表单中的记录源还是列表框或下拉列表的行源.
现在,重点是我不是要求用户输入这些情况,而是从Access对象中绘制条件值,例如窗体上的控件.现在,在大多数情况下,这将是对只有一个目的的表单的控制 - 收集某种形式的过滤的标准.该表单上没有未经验证的自由文本字段 - 日期字段将具有输入掩码(这将限制输入到有效日期),并且具有有限数量的有效值的字段将具有将选项限制为有效的控制类型数据.通常这会是下拉列表或选项组.
这种设计的原因不一定是为了避免SQL注入(虽然它会阻止这种情况),但是要确保用户不会因输入无效的标准而感到沮丧并且不会产生任何结果.
现在,另一个考虑因素是,有时您确实想要使用一些纯文本字段,以便用户可以放入某些尚未受限制的数据(例如查找名称).只是看一下我的一些具有未经验证的文本字段的名称查找例程的应用程序,我发现我没关系,因为我在这些情况下不使用BuildCriteria,因为它的设计目的是一次只收集一个标准(尽管用户可以输入"*"来检索多个记录.
如果我有一个文本框,用户输入"fent*或'a'='a'",我在WHERE子句中使用它:
WHERE tblDonor.LName Like "fent* or 'a' = 'a'"
结果是找不到任何东西.如果用户输入"fent*或a = a",它仍然不起作用,因为它是一个文本字段,我在它周围使用双引号.如果用户输入:
fent* or "a" = "a"
这也会破坏,因为当我的代码在它周围加上双引号时,WHERE子句将无效.
现在,只需使用输入并在其周围加上双引号,很明显输入:
" Or "fent*" or "a" = "a" Or "
会导致:
WHERE tblDonor.LName Like "" Or "fent*" or "a" = "a" Or ""
这将是非常糟糕的,因为它将返回一切.但是在我现有的应用程序中,我已经清除了用户输入中的双引号(因为双引号在LName字段中理论上是有效的),所以我的应用程序构造了这个WHERE子句:
WHERE tblDonor.LName Like "? Or ?fent*? or ?a? = ?a? Or ?*"
那不会返回任何行.
但它不是因为我试图避免SQL注入,而是因为我希望用户能够查找嵌入了双引号的名称.
======
一些结论:
在过滤数据时从不接受用户的自由格式输入 - 而是使用预验证输入的控件(例如,带有输入掩码的文本框,下拉列表,选项组)并将其限制为您知道有效的值.
当从文本框中接受数据而没有任何限制时,请避免使用Application.BuildCriteria,它将以一种方式处理输入,即用户可以欺骗您的应用程序返回所有行(尽管这是漏洞利用的程度).
这在实践中意味着,如果您想要收集多个条件,则需要以用户只能从预选值中进行选择的方式进行.最简单的方法是使用多选列表框(或其中一对使用ADD >>和其间的<< REMOVE命令按钮).
当然,您是否需要担心这种SELECT漏洞利用取决于所检索数据的重要性和隐私级别,以及确切地返回给用户的内容.在以不可编辑的形式(例如,报告)呈现数据时冒险返回所有非敏感数据行的风险可能没有问题,而如果您以可编辑的形式呈现数据并且有人更改了数据,则可能会出现问题.编辑.
但是对于非敏感数据,如果用户返回太多数据通常无关紧要(除了性能问题,例如,重载服务器 - 但在其他方面更好地处理).
所以,我对所有这些的看法:
永远不要使用InputBox()来收集标准(我已经避免了这个).
总是使用最有限的控制类型收集critiria(这已经是我经常做的事情).
如果使用文本框来收集字符串数据,则无论用户输入什么内容,都将其视为单一标准.
这确实意味着我有一些应用程序在那里用户可以输入"或'a'='a'"以及有效标准并返回所有行,但在这些应用程序中,这根本不是问题,因为数据不敏感.
但这是一个很好的提醒我不要自满.我原以为Application.BuildCriteria会保护我,但现在意识到Jet表达式服务在WHERE子句中接受的方式太宽容了.
2009/12/08编辑:刚刚在MS Access中找到了SQL注入的这些链接.所有这些都是针对Web注入的,因此不能直接应用于非Web SQL注入的讨论(其中许多会浪费时间在交互式Access中,因为您已经可以访问大量信息 - 强制,例如,关于文件系统,路径,可执行文件等的信息,但许多技术也可以在Access应用程序中工作.此外,从Access执行会打开许多无法从ODBC/OLEDB运行的功能.值得深思.
通过访问访问(PDF)
测试MS Access
MS Access SQL注入备忘单