非 Web SQL 注入

发布于 2024-07-13 00:08:12 字数 333 浏览 5 评论 0原文

人们似乎对 SQL 注入攻击有些歇斯底里。 最近,这里

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

如果我在 Excel 中创建连接到 Access 数据库的宏,我真的需要担心 SQL 注入吗? 它不在网络上,而是在我的办公室中使用(你们还记得台式机吗?)。 我不担心我的同事会破坏我。 如果他们足够聪明,可以执行 SQL 注入,那么他们难道还不够聪明,可以破解我的加载项密码并仅更改代码吗?

There seems to be some hysteria about SQL Injection attacks. Most recently, here

How to return the value in one field based on lookup value in another field

If I'm creating a macro in Excel that connects to an Access database, do I really have to be concerned about SQL injection? It's not on the web, it's used in my office (you guys remember desktops right?). I'm not concerned that my co-workers are going to sabotage me. If they're smart enough to do a SQL injection, aren't they smart enough to crack my add-in password and just change the code?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

逆蝶 2024-07-20 00:08:12

如果您在宏中构建 SQL,则它很容易受到 SQL 注入的攻击。 即使您信任将使用该东西的人,您至少应该注意基础知识,例如人们试图将单引号和分号字符放入数据库字段中。 在您的情况下,这并不是一个安全问题,而只是数据验证问题。

If you're building SQL in your macro, it's vulnerable to SQL injection. Even if you trust the people who will be using the thing, you should at least watch for the basics, like people trying to put single-quote and semicolon characters into database fields. this isn't so much a security issue in your case as just data validation.

[旋木] 2024-07-20 00:08:12

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

确定您的记录中不会有撇号 (')他们?

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

在这种情况下,即使没有人想要破解您的系统,您也会遇到错误。

SQL Injection is not just a security threat, it is a very real source of bugs too.

Are you sure that none of your records will ever have an apostophe (') in them?

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

In this case, you have a bug even though nobody wanted to crack your system.

老娘不死你永远是小三 2024-07-20 00:08:12

你永远不知道鲍比表什么时候会使用你的单词宏:

xkcd

you never know when bobby tables is going to use your word macro:

xkcd

已下线请稍等 2024-07-20 00:08:12

我想扩展我上面针对 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 or '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 or 'a' = 'a'”时会产生完全相同的 SQL。 正如你所说,由于 Jet 表达服务的工作方式,它将是完全开放的。

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

我从未见过任何针对此类操作的 Access 代码示例不建议使用参数化 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 子句将无效。

现在,在仅采用 use 输入并在其周围加上双引号的情况下,很明显输入 this:

" 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 注入,而是因为我希望用户能够查找嵌入双引号的名称。

======

一些结论:

  1. 在过滤数据时永远不要接受用户的自由格式输入——相反,使用预先验证输入的控件(例如,带有输入掩码的文本框、下拉列表、选项组)和限制 并

  2. 当不受限制地从文本框中接受数据时,请避免使用 Application.BuildCriteria,它会以用户可能欺骗您的应用程序返回所有行的方式处理输入(尽管这就是漏洞利用的范围) 。

这在实践中意味着,如果您想收集多个条件,则需要以用户只能从预选值中进行选择的方式来执行此操作。 最简单的方法是使用多选列表框(或一对中间带有 ADD>> 和 << REMOVE 命令按钮的列表框)。

当然,您是否需要担心这种 SELECT 漏洞取决于所检索数据的重要性和隐私级别,以及返回给用户的具体内容。 当以不可编辑的形式(例如报告)呈现数据时,冒返回所有非敏感数据行的风险可能没有问题,但如果您以可编辑的形式呈现数据并且有人更改了不应更改的数据,则可能会出现问题不予编辑。

但对于非敏感数据,如果用户返回太多数据,通常并不重要(性能问题除外,例如服务器超载——但这可以通过其他方式更好地处理)。

所以,我对这一切的看法是:

  1. 永远不要使用InputBox()来收集标准(我已经避免了这个)。

  2. 始终使用尽可能限制最多的控制类型来收集标准(这已经是我经常做的事情)。

  3. 如果使用文本框收集字符串数据,则无论用户输入什么内容,都将其视为单个条件。

    如果使用文本框收集字符串数据,则无论用户输入什么

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

但这是一个很好的提醒我不要自满。 我原以为 Application.BuildCriteria 会保护我,但现在意识到 Jet 表达式服务在 WHERE 子句中接受的内容过于宽容。

2009/12/08 编辑:刚刚在 MS Access 中的 SQL 注入上找到了这些链接。 所有这些都是针对 Web 注入的,因此不能直接适用于非 Web SQL 注入的讨论(其中许多在交互式 Access 中会浪费时间,因为您已经可以访问大量的暴力信息)强制的,例如有关文件系统、路径、可执行文件等的信息),但许多技术也适用于 Access 应用程序。 此外,从 Access 执行会打开许多​​无法从 ODBC/OLEDB 运行的功能。 值得深思。

I'd like to expand on the comment I made above in response to onedaywhen's post outlining how to exploit a SELECT statement in MS Access. Keep in mind that these are not generalized comments about how to protect from SQL injection, but apply specifically to programming in MS Access.

I've never seen any example code for Access that would allow the kind of exploit of a SELECT that onedaywhen outlined. The reason for this is that there's almost never a situation where you would use such simple methods for collecting criteria without some validation of the input somewhere along the way, not to avoid SQL injection, but to avoid bugs caused by invalid SQL.

Here's code implementing the simplest version of this:

Public Sub TestSQLExploit()
  Dim strSQL As String

  strSQL = "SELECT tblInventory.* FROM tblInventory WHERE InventoryID = "
  strSQL = strSQL & InputBox("Enter InventoryID")
  Debug.Print strSQL
End Sub

So, passing "10036 or 'a' = 'a'" produces this SQL:

SELECT tblInventory.*
FROM tblInventory
WHERE InventoryID=10036 Or 'a'='a'

And that's definitely not good!

Now, I would never write my code that way because I always want to allow for multiple values. Instead, if I were using the InputBox() function to collect the user input (which I honestly never do, since it's too hard to validate), I'd use Application.BuildCriteria to write the WHERE clause, since that would allow me to handle multiple criteria values. That would result in this code:

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

I honestly thought that Application.BuildCriteria would throw an error on this, but it doesn't, and when passed "10036 or 'a' = 'a'" produces exactly the same SQL. And because of the way the Jet expression service works, it would be wide open, as you say.

Now, I never ever actually write on-the-fly SQL like this, because I just don't like the InputBox() function, precisely because you have to write a bunch of code to validate the input. And if you used it like the code above, you'd have to do a lot to make sure it was valid.

I have never seen any Access code examples for this kind of operation that does not recommend using parameterized SQL (which would, of course, avoid the problem) or a Query-By-Form interface. I generally don't use saved parameter queries in Access, because I like to write my saved queries to be usable everywhere. This means they mostly don't have WHERE clauses that have criteria that change at runtime. When I use these saved queries I provide the WHERE clause for the appropriate situation, whether as a recordsource in a form or a rowsource for a listbox or dropdown list.

Now, the point here is that I'm not asking the user for input in these cases, but drawing the criteria values from Access objects, such as a control on a form. Now, in most cases, this would be a control on a form that has only one purpose -- to collect criteria for some form of filtering. There would be no unvalidated free-text fields on that form -- date fields would have input masks (which would restrict input to valid dates), and fields that have a limited number of valid values would have control types that restrict the choices to valid data. Usually that would be something like a dropdown or an option group.

The reason for that kind of design is not necessarily to avoid SQL injection (though it will prevent that), but to make sure that the user is not frustrated by entering criteria that are invalid and will produce no results.

Now, the other consideration is that sometimes you do want to use some plain text fields so the user can put in certain kind of data that is not already restricted (such as looking up names). Just looking at some of my apps that have name lookup routines with unvalidated text fields, I find that I'm OK, because I don't use BuildCriteria in those cases, because it's designed to collect only one criterion at a time (though the user can input "*" to retrieve multiple records).

If I have a textbox where the user enters "fent* or 'a' = 'a'", and I use that in a WHERE clause:

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

The result is that nothing is found. If the user entered "fent* or a = a", it will still not work, because it's a text field and I'm using double quote around it. If the user entered:

fent* or "a" = "a"

that will break, too, because when my code puts double quotes around it, the WHERE clause will be invalid.

Now, with the case of just taking use input and putting double quotes around it, it's clear that inputting this:

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

would result in:

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

and that would be very bad, since it would return everything. But in my existing applications, I'm already cleaning double quotes out of the user input (since double quotes are theoretically valid within the LName field), so my apps construct this WHERE clause:

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

That won't return any rows.

But the reason it doesn't is not because I was trying to avoid SQL injection, but because I want the user to be able to look up names that have double quotes embedded in them.

======

Some conclusions:

  1. never accept free-form input from users when filtering data -- instead, use controls that pre-validate input (e.g., textboxes with input masks, dropdown lists, options groups) and limit it to values that you know are valid.

  2. when accepting data from a textbox with no restrictions, avoid Application.BuildCriteria, which will process the input in such a way that the user could trick your app into returning all rows (though that's the extent of what the exploit could do).

What this means on a practical basis is that if you want to collect multiple criteria, you need to do it in a way that the user can only choose from preselected values. The simplest way to do that is with a multiselect listbox (or a pair of them with ADD>> and <<REMOVE command buttons in between).

Of course, whether or not you need to worry about this kind of SELECT exploit depends on the importance and privacy level of the data being retrieved, and exactly what is being returned to the user. It might be no problem to risk returning all rows of non-sensitive data when presenting the data in an uneditable form (e.g., a report), whereas it might be problematic if you presented it in an editable form and someone changed data that oughtn't be edited.

But with non-sensitive data, it will often simply not matter if the user gets too much data returned (except for performance issues, e.g., overloading a server -- but that's better handled in other ways).

So, my takeaway on all of this:

  1. never use InputBox() to collect criteria (this one I already avoid).

  2. always use the most limiting control types possible for collecting critiria (this is already something I do regularly).

  3. if using a textbox to collect string data, treat it as a single criterion no matter what's put in by the user.

This does mean that I have some apps out there where a user could input "Or 'a' = 'a'" along with a valid criterion and return all rows, but in those apps, this is simply not an issue, as the data is not sensitive.

But it's a good reminder to me not to be complacent. I had thought that Application.BuildCriteria would protect me, but now realize that the Jet expression service is way too forgiving in what it accepts in a WHERE clause.

2009/12/08 EDIT: Just found these links on SQL Injection in MS Access. All of these are targetted at web injection, so not directly applicable to a discussion of Non-Web SQL injection (many of them would be a waste of time in interactive Access, as you already have access to a lot of the information being brute-forced, e.g., information about file system, paths, executables, etc.), but many of the techniques would also work in an Access application. Also, executing from Access opens up a lot of functions that would not be runnable from ODBC/OLEDB. Food for thought.

乖乖哒 2024-07-20 00:08:12

老实说,如果这是您正在谈论的现有应用程序,我不会去重写它。 但是,如果您正在开发它,那么我不认为使用参数化查询而不是替代方案有那么困难。

Honestly, if this is an existing app you're talking about, I wouldn't go rewrite it. However, if you are developing it as we speak, I can't see it being that hard to use parameterized queries instead of the alternative.

冬天旳寂寞 2024-07-20 00:08:12

作为开发人员,您对应用程序所保存的数据的安全性负责(即使不是全部,至少也是部分负责)。

无论您的申请是在线申请还是仅在办公室使用,都是如此。 尽一切努力确保您的数据存储无懈可击。

归根结底,您不想成为那个必须向老板解释去年销售数据去向的人。

As a developer, you are responsible, if not wholly then at least in part, for the security of the data held by your application.

This is true whether your application is online or used only in your office. Do everything you can to ensure your data store is airtight.

At the end of the day, you don't want to be the one who has to explain to the boss where last year's sales figures have gone.

小巷里的女流氓 2024-07-20 00:08:12

物理安全始终是数据安全的第一道防线。 如果您的应用程序仅在办公室内部分发,并且所访问的数据价值不足以让某人费尽心思窃取和破解,那么您可以遵守比在外部使用的安全标准更低的安全标准。面向网络应用程序。

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

一个好的经验法则是问自己:如果我在充分了解该产品的情况下想要用它来伤害我的公司,我会造成多大的损失? 然后,建立足够的安全性,将这个数字降低到可以容忍的水平。

Physical security is always the first line of defense in data security. If your application is only going to be distributed inside an office and the data accessed is of insufficient value for someone to go to the trouble and expense of stealing and cracking, you can adhere to a lower security standard than you would use on an outward-facing web application.

But, real security is ultimately about what can happen, not what we expect to happen. If your application handles data entrusted to you by the public (SSNs, credit card numbers, etc) or if it is the only repository of data crucial to your company, you have to take into account what potentially malicious users could do with your code in the future. Today's happy employee is tomorrow's disgruntled sociopath.

A good rule of thumb is to ask yourself: If I, with full knowledge of this product, wanted to use it to hurt my company, how much damage could I do? Then, build in enough security to bring that number down to tolerable levels.

水染的天色ゝ 2024-07-20 00:08:12

没有。(是。) 是。 :)

我经常看到开发人员浪费宝贵的资源来加固“前门”,却没有注意到后面的旋转纱门。 这通常类似于将前端强化为不安全的后端、强化基本上对不同用户开放的应用程序等……

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

No. (Yes.) Yes. :)

Oftentimes, I see developers wasting precious resources on fortifying the "front door", only to not notice the swinging screen door on the back. This is usually something like fortifying a frontend to an insecure backend, fortifying an app that is basically open to varied users, etc...

It's all nice and well to make blanket statement about security, but it must match requirements.

莫相离 2024-07-20 00:08:12

IMO 如果您的系统将暴露给那些可能想要造成伤害的人(例如在互联网上),那么您确实应该防止 SQL 注入。

另一方面,如果它是一个内部系统,任何可以访问 SQL 注入的恶意用户也可能以其他方式对其造成损害,那么它确实不是那么重要。

我自己编写的代码很容易受到 SQL 注入的攻击,但无论如何,唯一具有这种访问权限的人是具有 SQL 访问权限的同事。

IMO if your system will be exposed to people who may wish to cause harm (e.g. on the Internet), then you really should protect against SQL injection.

On the other hand, if it is an internal system, where any malicious user who could access SQL injection could also harm it in other ways anyway, then it really is not that important.

I have written code myself which is vulnerable to SQL injection, but the only people with that sort of access are co-workers with SQL access anyway.

夜唯美灬不弃 2024-07-20 00:08:12

尽管我们都希望应用程序能够免受任何攻击,但开发所有防弹功能所花费的时间必须与额外的好处一起权衡。 如果您可以合理地预期安全要求不会很高,那么您可能希望放弃这一点。 如果您认为这可能是值得担心的事情,也许您现在应该采取措施来防止这种可能性,而不必再担心了。

Although we all would like applications that are invulnerable to any and all attacks, the time taken developing all of the bulletproofing has to be weighed alongside with the added benefit. If you can reasonably expect the security requirements to not be very high, this could be something you might want to pass on. If you think it is something potentially to worry about, maybe you should take the steps to prevent the possibility now and not have to worry anymore.

他夏了夏天 2024-07-20 00:08:12

如果我在 Excel 中创建一个宏
连接到 Access 数据库,我可以吗
确实需要关心 SQL
注射?

或许。 这取决于,真的。 我个人不会担心,
但是您想要存储什么类型的数据以及它的敏感性是什么?

如果他们足够聪明来执行 SQL
注射,他们难道不够聪明吗
破解我的加载项密码,然后
更改代码?

或许。 仅仅因为有人可以进行 SQL 注入并不意味着他们足够聪明
破解您的加载项密码。 另一方面,他们也可能是这样。

If I'm creating a macro in Excel that
connects to an Access database, do I
really have to be concerned about SQL
injection?

Maybe. It depends, really. I personally wouldn't be concerned,
but what kind of data are you trying to store and what is it's sensitivity?

If they're smart enough to do a SQL
injection, aren't they smart enough to
crack my add-in password and just
change the code?

Maybe. Just because someone can do a sql injection does not mean they are smart enough
to crack your add-in password. On the other hand, they could be.

无法言说的痛 2024-07-20 00:08:12

迪克,这取决于你如何处理参数。 下面是一个如何不做某事的 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

那么生成的 SQL 字符串将是这样的:

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

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

更好的方法是使用带有参数对象的预准备语句,例如 ADODB.Command 对象。

杰米。

--

Dick, It depends how you are handling parameters. Here's a VBA example of how not to do things:

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

Consider that if some wag, instead of typing their account ID into the textbox (txtAccountOwnerID), actually typed this:

dummy' OR 'a' = 'a

then the resulting SQL string would be this:

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

Not good becasue the 'a' = 'a' predicate would resolve to TRUE and all accounts would be deleted.

Better would be to use a prepared statement using Parameter objects e.g. ADODB.Command object.

Jamie.

--

梦纸 2024-07-20 00:08:12

三点:

  1. 使用参数化查询通常比转义破坏 SQL 的可能方法(例如奥尼尔先生)要简单,这样您就可以将数据直接连接到查询字符串中。 如果更健壮的选项实现起来也更少,那么您为什么不想想要这样做呢?

  2. 我已经很久没有使用 Jet 了,所以我不知道它现在是否支持预先准备的语句,但是,如果您要多次运行该语句,请使用参数化查询和使用不同的参数重新运行它会比每次构建新查询更快。

  3. 即使所有用户都 100% 值得信赖,并且永远不会因为不满而试图造成任何损害,但仍然有可能出现拼写错误或其他真正的错误。 防止用户错误通常被认为是一件好事。

因此,即使不是为了安全起见,您绝对应该使用参数化查询,如 Spolsky 对另一个问题的答复所示。 它们不仅更安全,而且更防错,通常编写速度更快,并且对于重复查询具有更高的性能。

Three points:

  1. Using parametrized queries is generally less work than escaping possible ways to break your SQL (Mr. O'Neill, for instance) so that you can concatenate the data into the query string directly. If the more robust option is also less work to implement, then why would you not want to do it?

  2. I haven't used Jet for ages, so I don't know whether it supports pre-prepared statements these days or not, but, if you're going to run the statement more than once, using a parametrized query and re-running it with different parameters will be faster than building new queries each time.

  3. Even if all users are 100% trustworthy and will never become disgruntled enough to attempt to cause any damage, there's always the possibility of typos or other genuine mistakes. Guarding against user error is generally considered a Good Thing.

So you absolutely should use parametrized queries, as shown in Spolsky's reply to the other question, even if not for the sake of security. They're not just more secure, they're also more error-resistant, often quicker to write, and are higher-performance for repeated queries.

可可 2024-07-20 00:08:12

>使用参数化查询并使用不同的参数重新运行它会比每次构建新查询更快。

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

第 18 页

由于存储查询有一个预编译的查询计划,参数化查询包含索引列上的参数可能无法有效执行。 由于查询引擎事先并不知道要在参数中传递的值,因此它只能猜测最有效的查询计划。 根据我们检查的客户性能场景,我们发现在某些情况下,通过用临时查询替换存储的参数化查询可以实现显着的性能提升。 这意味着在代码中创建 SQL 字符串并将其传递给数据库对象的 DAO OpenRecordset 或 Execute 方法

是吧? 而且,以上的情况我都经历过!

请记住,查询计划的编译时间无论如何都是数千秒。 我的意思是,实际上,查询计划时间从 0.01 到 0.0001。 当然,它快了 100 倍,但这仅仅为我们节省了百分之一秒。 我们运行一个报告需要 2 秒,因此查询计划时间根本不是问题。

今天我们有大量的加工。 磁盘驱动器、内存和网络 I/O 速度是瓶颈。 我们也不存在为提交到 JET 的每个新 sql 字符串浪费服务器 sql 查询缓存的问题。 无论如何,那些内联 sql 查询计划都不会被缓存。 而且,更重要的是,JET 是基于客户端的引擎,因此当您的办公室 LAN 上有 10 个用户时,您将在每台计算机上本地运行 10 个 JET 副本。 查询计划缓存不像 SQL Server 那样是一个问题。

正如上面的 jet 白皮书(以及我的经验)所示,通过强制重新编译不带参数的 sql 来获得更好的查询计划的好处超过了使用带参数的预编译查询计划的好处。

然而,为了保持正轨,必须同意大卫的观点。 我不认为当你使用 odbc 时,或者在本例中使用 dao 对象模型 + jet 时,我无法想出任何方法来注入真正的 sql 语句。

人们也许可以通过上面“蹩脚”的 InputBox() 示例输入可能产生意外结果的条件。 正如所指出的,内置于​​访问中的应用程序并不经常以这种方式工作。

对于删除记录之类的操作,您将查看一个表单,它将有一个自定义菜单栏(或现在的功能区),或者只是在表单上放置一个删除按钮。 因此,用户无法为此类删除代码输入错误数据。

更重要的是,当我们经常接受用户在表单上的输入时,请记住我们的表单具有内置的数据掩码。 毕竟这正是 MS Access 的设计目的。 因此,如果我们要求提供电话号码,用户无法为该输入掩码输入字母,甚至无法输入任何非数字字符。 该掩码甚至会在该电话号码的适当位置放入 () 和 - 进行显示,但在用户实际输入中只会显示数字。

对于大多数其他类型的提示,我们使用组合框、lisbox 和其他 UI 元素,这些元素再次限制了用户向文本框中注入表单允许的内容以外的内容的能力。

由于如此丰富的屏蔽和输入能力远远超出了大多数屏幕构建器的范围,因此对于基于 MS Access 的应用程序来说,注入是一个罕见的话题。

如果有人可以展示一个 JET 示例,其中用户可以通过注入执行 sql 语句,我会洗耳恭听,因为我认为使用 dao + jet 是不可能的。

对于 MS-access 应用程序来说,这也许是可能的,但在实际操作中,这又是非常困难的。

>using a parametrized query and re-running it with different parameters will be faster than building new queries each time.

Actually, it will not improve performance in jet if you talking about query performance. In fact, from the JET white paper “Performance Overview and Optimization Techniques”, we get this gem:

page 18

Since stored queries have a precompiled query plan, parameterized queries that contain parameters on indexed columns may not execute efficiently. Since the query engine does not know the values to be passed in a parameter in advance, it can only guess as to the most efficient query plan. Based on customer performance scenarios that we have examined, we have discovered that in some instances substantial performance gains can be achieved by replacing a stored parameterized query with a temporary query. This means creating the SQL string in code and passing it to the DAO OpenRecordset or Execute methods of the Database object

Neat-o eh? And, I have experienced the above!

Keep in mind that the compile time for a query plan is in the 1000’s of a second anyway. I mean, really, the query plan time goes from .01 to .0001. Sure it 100 times faster, but that is only saving us a 100th of a second overall. We running a report that takes 2 seconds so that query plan time is not even a concern.

We have GOBS of processing today. It is disk drives, memory and the network i/o speeds that are the bottle necks. We also don’t have the issue of wasting up the server sql query cache for each new sql string submitted to JET. Those in-line sql queries plans are not cached anyway. And, MORE important JET is client based engine so when you have 10 users on your office lan, you have 10 copies of JET running local on each machine. Query plan cache is not an issue like it is for sql server.

As the above jet white paper shows (and my experience), the benefits of a better query plan by forcing a re-compiling of that sql without parameters outweighs the benefits of having a pre-complied query plan with paramaters.

However, to stay on track, have to agree with David. I don’t think that when you using odbc, or in this case the dao object model + jet, I can’t come up with ANY WAY to inject a real sql statement.

One can perhaps with the “lame” InputBox() example above enter conditions that might produce unexpected results. As pointed out applications built in access don’t work this way very often.

For things like deleting a record you be viewing a form and it will have a custom menu bar (or now ribbon), or simply a delete button placed on the form. The user thus can’t enter bad data for this type of deleting code.

MORE important when we do often accept input from users on forms, keep in mind our forms have built-in data masks. After all this is quite much what MS access was designed for. Hence if we are asking for a phone number, the user can’t enter letters or even any non numeric charters for that input mask. That mask will even put in () and – in the appropriate places in that phone number for display, but only numbers will in in the users actual input.

For most other types of prompts we use combo boxes, lisboxes and other UI elements that again limits the users ability to inject something other then what that form allows into that text box.

Due to such an affluent number of masking and input abilities that are far beyond most screen builders, injecting is rare topic for MS access based applications.

If anyone can show an JET example in which the user can execute a sql statement by injection, I am all ears as I don’t think it is possible with dao + jet.

For an MS-access applications, it might be possible, but once again, in actual practice, very difficult.

嘿嘿嘿 2024-07-20 00:08:12

有人可以发布使用 Jet 数据库作为后端的 SQL 注入的上下文证明 Excel VBA 代码吗? 或者在如何返回一个字段中的值中准确演示哪些参数可以传递给代码基于另一个字段中的查找值,这会造成破坏(而不仅仅是破坏代码)?

鉴于 Jet 无法执行由“;”分隔的多个 SQL 语句,我很难想象 Jet 后端存在任何 SQL 注入威胁。 但也许那是因为我不像黑客那样富有想象力。

哦,免费线索(关于传统 SQL 注入以外的危险主题):

  1. Access 表达式服务无法通过 ODBC 获得。

  2. 可以通过DDE获得,但我不知道是否可以通过DDE将SQL传递给Access(我已经大约10年没有在Access中使用DDE了)。

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

Would someone please post proof-of-context Excel VBA code for SQL injection using a Jet database as the back end? Or demonstrate exactly what parameters could be passed to the code in How to return the value in one field based on lookup value in another field that would be damaging (rather than just breaking the code)?

Given that Jet cannot execute multiple SQL statements separated by ";", I'm having a hard time conceiving of any SQL injection threat with a Jet back end. But perhaps that's because I'm just not as imaginative as hackers.

Oh, a free clue (on the subject of dangers other than traditional SQL injection):

  1. the Access expression service is unavailable via ODBC.

  2. it is available via DDE, but I don't know if you can pass SQL to Access via DDE (I haven't used DDE with Access in about 10 years).

  3. if you know nothing about the Access and Jet expression services, you're probably not qualified to be answering a question about Jet (and Access).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文