非networkingSQL注入

似乎有一些关于SQL注入攻击的歇斯底里。 最近在这里

如何根据另一个字段中的查找值返回一个字段中的值

如果我在Excel中创build一个连接到Access数据库的macros,我真的不得不关心SQL注入吗? 这不是在networking上,它在我的办公室使用(你们记得桌面?)。 我不担心我的同事要破坏我。 如果他们足够聪明的做一个SQL注入,是不是足够聪明来破解我的加载项密码,只是改变代码?

如果你在你的macros中构buildSQL,它很容易被SQL注入。 即使你信任那些将要使用这个东西的人,你至less应该注意一些基本的东西,比如试图把单引号和分号字符放到数据库字段中的人。 这不仅仅是数据validation的安全问题。

SQL注入不只是一个安全威胁,它也是一个非常真实的错误来源。

确定你的logging中没有一个会有一个启示(')吗?

INSERT INTO NAMES (FIRSTNAME, LASTNAME) VALUES('Jack', 'O'Neill') 

在这种情况下,即使没有人想破解你的系统,你也有一个bug。

你永远不知道什么时候bobby桌子会使用你的单词macros:

xkcd

我想在上面的评论中对onedaywhen的post作出回应,概述如何利用MS Access中的SELECT语句。 请记住,这些不是关于如何防止SQL注入的一般性评论,而是专门应用于MS Access中的编程。

我从来没有见过任何Access示例代码,允许在概述时使用SELECT的某种利用。 这样做的原因是,几乎从来没有一种情况下,您会使用这种简单的方法来收集标准,而不是在某种程度上validationinput,而不是避免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()函数来收集用户input(我真的从来没有这样做,因为它太难以validation),我会使用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时。 正如你所说,由于Jetexpression服务的工作方式,它将是开放的。

现在,我从来没有真正写过这样的dynamicSQL,因为我只是不喜欢InputBox()函数,正因为你必须编写一堆代码来validationinput。 如果你像上面的代码一样使用它,你必须做很多事情来确保它是有效的。

我从来没有见过任何这种操作的Access代码示例,不build议使用参数化的SQL(这当然会避免该问题)或逐个查询的界面。 我通常不使用保存在Access中的参数查询,因为我喜欢写我保存的查询到处可用。 这意味着他们大多没有WHERE子句,其条件在运行时会发生变化。 当我使用这些保存的查询时,我为相应的情况提供了WHERE子句,无论是作为表单中的logging源还是列表框或下拉列表的行源。

现在,重点在于,在这些情况下,我不要求用户input,而是从Access对象(如窗体上的控件)中绘制条件值。 现在,在大多数情况下,这将是一个只有一个目的的表单控制 – 收集某种forms的过滤标准。 该表单上没有未经validation的自由文本字段 – date字段将具有input掩码(将限制input为有效date),并且具有有限数量有效值的字段将具有控制types,从而将选项限制为有效数据。 通常这将是像下拉菜单或选项组。

这种devise的原因不一定是为了避免SQL注入(虽然它会阻止),但是要确保用户不会因为input无效的标准而产生任何结果而感到沮丧。

现在,另一个考虑是,有时候你想要使用一些纯文本字段,这样用户就可以放入一些不受限制的数据(比如查找名字)。 只是看看我的一些应用程序名称查找例程与未validation的文本字段,我发现我没事,因为我使用BuildCriteria在这种情况下,因为它的目的是一次只收集一个标准(虽然用户可以input“*”来检索多条logging)。

如果我有一个用户input“fent *”或“a”=“a”的文本框,我在WHERE子句中使用它:

 WHERE tblDonor.LName Like "fent* or 'a' = 'a'" 

结果是没有发现任何东西。 如果用户input“fent *或a = a”,它将仍然不起作用,因为它是一个文本字段,我使用双引号。 如果用户input:

 fent* or "a" = "a" 

这也将打破,因为当我的代码放在双引号,WHERE子句将是无效的。

现在,只是在使用input和双引号的情况下,很明显,input这个:

 " Or "fent*" or "a" = "a" Or " 

会导致:

 WHERE tblDonor.LName Like "" Or "fent*" or "a" = "a" Or "" 

这将是非常糟糕的,因为它会返回一切。 但是在我现有的应用程序中,我已经从用户input中清除了双引号(因为双引号在LName字段中理论上是有效的),所以我的应用程序构造了这个WHERE子句:

 WHERE tblDonor.LName Like "? Or ?fent*? or ?a? = ?a? Or ?*" 

这不会返回任何行。

但其原因并不是因为我试图避免SQL注入,而是因为我希望用户能够查找embedded双引号的名称。

======

一些结论:

  1. 在过滤数据时不要接受来自用户的自由格式input – 而是使用预先validationinput的控件(例如,带有input掩码,下拉列表和选项组的文本框),并将其限制为您知道有效的值。

  2. 当接受没有限制的文本框中的数据时,避免使用Application.BuildCriteria来处理input,这样用户可以欺骗你的应用程序返回所有的行(虽然这是利用漏洞的程度)。

这意味着在实践基础上,如果你想收集多个标准,你需要这样做,用户只能从预选的值中select。 最简单的方法是使用多选列表框(或两者之间的ADD >>和<< REMOVE命令button)。

当然,您是否需要担心这种SELECT利用取决于正在检索的数据的重要性和隐私级别,以及返回给用户的确切内容。 当以不可编辑的forms(例如报告)呈现数据时,冒险返回所有非敏感数据行可能是没有问题的,而如果以可编辑的forms呈现数据并且某人改变了应该“不要编辑。

但是对于非敏感数据,如果用户获取的数据太多(除了性能问题,例如,服务器超载,但是用其他方式更好地处理),通常都不会有影响。

所以,我的所有这一切:

  1. 从来没有使用InputBox()来收集标准(这一个我已经避免)。

  2. 总是使用最有限的控制types来收集critiria(这已经是我经常做的事了)。

  3. 如果使用文本框来收集string数据,则不pipe用户input什么内容,都将其视为单个标准。

这确实意味着我有一些应用程序在那里用户可以input“或'a'='a'”以及有效的标准并返回所有的行,但在这些应用程序中,这不是一个问题,因为数据不敏感。

但是,对我来说这不失为一种自满的感觉。 我曾经认为Application.BuildCriteria会保护我,但现在认识到Jetexpression式服务对于WHERE子句中所接受的内容也是宽容的。

2009/12/08编辑:刚才发现MS Access中的SQL注入这些链接。 所有这些都是针对网页注入的,所以不能直接适用于非Web SQL注入的讨论(其中很多会浪费时间在交互式Access中,因为您已经可以访问大量的信息,强制的,例如关于文件系统,path,可执行文件等等的信息),但是许多技术也可以在Access应用程序中工作。 另外,从Access执行会打开很多不能从ODBC / OLEDB运行的函数。 食物的思想。

  • 通过访问访问(PDF)
  • testingMS Access
  • MS Access SQL注意事项表

作为一名开发人员,如果您的应用程序所拥有的数据的安全性不是完全保证,那么您至less应负责任。

无论您的应用程序是在线还是仅在您的办公室使用,都是如此。 尽你所能确保您的数据存储是密封的。

在这一天结束的时候,你不想成为去年销售数字已经去向老板解释的人。

老实说,如果这是你正在谈论的现有应用程序,我不会去重写它。 但是,如果你正在开发它,我不能看到这是很难使用参数化的查询,而不是替代。

物理安全始终是数据安全的第一道防线。 如果你的应用程序只是在办公室内部进行分发,而且访问的数据对于人们来说是不值钱的,而且窃取和破解的麻烦和费用是不够的,那么你就可以坚持一个比你在外部使用的安全标准更低的安全标准,面向web应用程序。

但是,真正的安全最终是关于可能发生的事情,而不是我们预期会发生的事情。 如果您的应用程序处理公众委托给您的数据(SSN,信用卡号码等),或者它是唯一对您公司至关重要的数据存储库,那么您必须考虑哪些潜在的恶意用户可以使用您的代码未来。 今天的快乐员工是明天不满的反社会人士。

一个好的经验法则就是问自己:如果我充分了解这个产品,想用它来伤害我的公司,那么我可以做多less伤害呢? 然后,build立足够的安全性,把这个数字降到可以接受的水平。

没有(是)是的。 🙂

我经常看到开发商浪费宝贵的资源来强化“前门”,只是没有注意到后面的摇动的屏幕门。 这通常就像增强了一个前端不安全的后端,强化了基本上向不同用户开放的应用程序等等。

关于安全性的一揽子声明是很好的,但它必须符合要求。

国际海事组织如果你的系统将暴露给可能会造成伤害的人(例如在互联网上),那么你真的应该防范SQL注入。

另一方面,如果是内部系统,任何可以访问SQL注入的恶意用户也可能以其他方式对其进行破坏,那么实际上并不重要。

我自己编写的代码很容易受到SQL注入的影响,但只有那些具有这种访问权限的人才是SQL访问的同事。

虽然我们都希望那些无法攻击任何攻击的应用程序,但是开发所有防弹技术所花费的时间必须与额外的好处一起衡量。 如果您可以合理地预期安全性要求不会很高,那么这可能是您可能想要传递的内容。 如果你认为这是可能担心的事情,也许你应该采取措施,防止现在的可能性,而不必再担心。

如果我在Excel中创build一个连接到Access数据库的macros,我真的不得不关心SQL注入吗?

也许。 这取决于,真的。 我个人不会担心,但是你想要存储什么types的数据,它的敏感度是多less?

如果他们足够聪明的做一个SQL注入,是不是足够聪明来破解我的加载项密码,只是改变代码?

也许。 只是因为有人可以做一个SQL注入并不意味着他们足够聪明来破解你的加载项密码。 另一方面,他们可能是。

迪克,这取决于你如何处理参数。 下面是一个VBA如何不做事情的例子:

 Friend Function DeleteAnAccount() As Boolean Const SQL_DELETE_AN_ACCOUNT As String * 50 = _ "DELETE FROM Accounts WHERE account_owner_ID = '?';" Dim sql As String sql = Replace$(SQL_DELETE_AN_ACCOUNT, "?", txtAccountOwnerID.Text) m_Connection.Execute sql End Function 

考虑一下,如果一些摇摆,而不是键入他们的帐户ID到文本框(txtAccountOwnerID),实际上键入这个:

 dummy' OR 'a' = 'a 

那么生成的SQLstring将是这样的:

 DELETE FROM Accounts WHERE account_owner_ID = 'dummy' OR 'a' = 'a'; 

不好,因为'a' = 'a'谓词将parsing为TRUE ,所有帐户都将被删除。

更好的办法是使用一个准备的语句使用参数对象,例如ADODB.Command对象。

杰米。

三点:

  1. 使用参数化查询通常比转义可能的方式来破坏SQL(例如奥尼尔先生)的工作要less,以便您可以将数据直接连接到查询string。 如果更强大的选项也是较less的工作来执行,那么为什么你不想这样做呢?

  2. 我还没有使用Jet的年龄,所以我不知道它是否支持这些日子预先准备好的语句,但是,如果你打算不止一次地运行语句,使用参数化查询和重新运行它具有不同的参数将比每次build立新的查询更快。

  3. 即使所有的用户都是100%可信赖的,永远不会因为试图造成任何损害而变得不满,总会有错别字或其他真正的错误的可能性。 防范用户错误通常被认为是一件好事。

所以你绝对应该使用参数化查询,就像Spolsky对另一个问题的回答所示,即使不是为了安全起见。 它们不仅更安全,而且更具有防错能力,写入速度更快,而且对重复查询的性能更高。

>使用参数化查询并使用不同的参数重新运行它将比每次创build新的查询更快。

事实上,如果谈论查询性能,它不会提高性能。 事实上,从JET白皮书“性能概述和优化技术”中,我们得到了这个gem:

第18页

由于存储的查询具有预编译的查询计划,因此包含索引列上的参数的参数化查询可能无法有效执行。 由于查询引擎并不知道要在参数中传递的值,所以只能猜测最有效的查询计划。 根据我们所检查的客户性能情况,我们发现在某些情况下,通过用临时查询replace已存储的参数化查询可以获得实质性的性能提升。 这意味着在代码中创buildSQLstring并将其传递给数据库对象的DAO OpenRecordset或Execute方法

整洁啊? 而且,我已经体验了以上!

请记住,查询计划的编译时间无论如何都在1000秒之内。 我的意思是,查询计划的时间实际上是从.01到.0001。 当然,速度要快100倍,但这只能为我们节省100秒。 我们运行一个需要2秒钟的报告,这样查询计划时间甚至不是问题。

我们今天有GOBS的加工。 它是磁盘驱动器,内存和networkingI / O速度是瓶颈。 我们也没有为提交给JET的每个新的sqlstring浪费服务器sql查询caching的问题。 那些内嵌的sql查询计划不会被caching。 而且,更重要的JET是基于客户端的引擎,所以当你的办公室局域网上有10个用户时,每台机器上都有10个本地运行的JET副本。 查询计划caching不像它是为SQL服务器的问题。

正如上面的jet白皮书显示的(以及我的经验),通过强制重新编译没有参数的sql,更好的查询计划的好处超过了使用参数进行预编译的查询计划的好处。

但是,要保持正轨,不得不同意大卫。 我不认为当你使用odbc,或者在这种情况下,道对象模型+ jet,我不能拿出任何方式注入一个真正的sql语句。

也许可以用上面的“蹩脚的”InputBox()例子input可能产生意外结果的条件。 正如所指出的那样,内置访问的应用程序并不经常这样工作。

对于删除logging等事情,您正在查看一个表单,它将有一个自定义的菜单栏(或现在的function区),或者只是一个删除button放在窗体上。 因此,用户不能为这种types的删除代码input不好的数据。

更重要的是,当我们经常接受用户在表单上的input时,请记住我们的表单有内置的数据掩码。 毕竟这是相当多的MS访问devise。 因此,如果我们要求一个电话号码,用户不能input字母,甚至input掩码的任何非数字章程。 该面具甚至可以放入()和 – 在该电话号码的适当位置进行显示,但只有数字会在用户的实际input中。

对于大多数其他types的提示,我们使用combobox,句柄和其他用户界面元素,这再次限制了用户注入其他东西的能力,那么这种forms允许到文本框中。

由于如此丰富的屏蔽和input能力远远超出了大多数屏幕制作者,所以注入是基于MS访问的应用的罕见主题。

如果任何人都可以显示一个JET的例子,在这个例子中用户可以通过注入来执行一个sql语句,所有我都觉得,因为我不认为用dao + jet是可能的。

对于MS访问应用程序来说,这可能是可能的,但是在实际操作中再一次很困难。

会有人请张贴使用Jet数据库作为后端SQL注入的上下文Excel VBA代码吗? 或者说明究竟哪些参数可以传递到代码中如何根据另一个字段中的查找值来返回一个字段中的值,这会损害(而不是破坏代码)?

由于Jet无法执行以“;”分隔的多个SQL语句,因此我很难用Jet后端构想任何SQL注入威胁。 但也许这是因为我只是没有黑客那么有想象力。

哦,一个自由的线索(关于传统SQL注入以外的危险):

  1. Accessexpression式服务通过ODBC不可用。

  2. 它可以通过DDE,但我不知道你是否可以通过DDE通过SQL访问(我在10年左右没有使用DDE的DDE)。

  3. 如果您对Access和Jetexpression式服务一无所知,则可能没有资格回答关于Jet(和Access)的问题。