【问题标题】:What character sanitation do I need for an MS Access Pass Through Query to SQL ServerMS Access Pass Through Query to SQL Server 需要什么字符卫生
【发布时间】:2018-02-13 05:36:11
【问题描述】:

我正在尝试将 MS Access 与 SQL Server 连接,并且我想确保我不会受到 SQL 注入攻击。

我看到了使用 ADO 创建查询的参数化版本的建议,但我想了解如何使用 DAO 传递来清理我的输入。

目前我正在转义单引号和反斜杠。

VBA 中是否有任何标准的 SQL Server 注入清理方法?

【问题讨论】:

  • “清理你的输入”意味着传递你的参数作为参数正确操作时,无需转义单引号。无论您逃避什么,都不会像不将用户输入连接到您的查询中那样安全,无论如何。如果您的数据库驱动程序不支持参数化查询,请使用支持的查询。参数值是数据,不是可执行代码:不要这样对待它们,你会做得很好。
  • @Mat'sMug 但是必须有一组有限的字符才能正确转义以使字符串数据安全。 ADO 代码本身(即将参数转换为安全的查询值)最终必须完成这个问题所要求的内容,因此社区应该真正理解理解和复制该行为。 SQL 注入只是专家程序员在必要时应该能够识别和处理自己的一种漏洞。欢迎提出好的建议,但不应阻止直接回答此类问题。
  • @CPerkins 这不是 ADO 的工作方式。参数独立于查询传递到 SQL 服务器,以不存在 SQL 注入风险的方式。例如,在使用 SQL Server 审核时,您可以看到这一点,其中记录了查询,但这些查询中使用的参数没有。但是,您也许可以编写转义方法,但这需要大量工作。不管怎样,Are there any standard SQL Server injection sanitation methods in VBA?这个问题的答案只是一个简单的NO!
  • @CPerkins 肯定有一个简单的答案:A) 没有标准方法,因为你不这样做和 B) 不要自己动手。其他任何东西都是一种虚假的安全感,会改变合法数据。仅供参考 ADO 不会将参数连接到查询中;在您的数据库服务器上运行探查器并自行查找。不要做服务器的工作。不要自己滚。不要这样做。 是信息安全专家的标准答案。
  • @Mat'sMug 知道了。但是为什么不添加您的评论作为答案呢?甚至把标题改成文中的问题?对类似术语和概念的非详尽搜索确实有很多答案,包括使用 ADO 调用参数化存储过程,但也有很多不安全的示例。作为直接答案,它对社区来说是普遍使用的。

标签: sql-server vba ms-access pass-through


【解决方案1】:

VBA 中有没有标准的 SQL Server 注入清理方法?

不。如果有的话,我会非常担心。我不做 PHP,但我读过关于它的“标准 SQL 注入清理方法”的恐怖故事。看看带有 标记的Code Review 问题 - 很多人都在问“这段代码安全吗?”,除非他们使用准备好的语句,否则答案总是“不”。

');--DROP TABLE Users;-- 是在UserName 数据库字段中看到的一个相当可疑的值(您认为这个答案的文本存储在哪里?),但是如果您正确编写了数据访问代码,则没有理由即使您的登录被授权(服务器端)执行这样的语句,它也会造成任何混乱。

问题不在于用户的输入。问题在于将用户输入连接到可执行 SQL 中,从而将用户输入视为可执行代码


想要是执行一个常量 SQL 语句。当你这样做时:

' *** DON'T DO THIS ***
Dim sql As String
sql = "SELECT Id FROM dbo.Users WHERE UserName = '" & pName & "';"

那么每次将SQL语句发送到服务器时,都是一个不同的查询:服务器甚至不知道涉及到一个参数,它所看到的只是:

SELECT Id FROM dbo.Users WHERE UserName = ''');--DROP TABLE Users;--';

注意多余的单引号;如果您在想嘿,SQL 注入被阻止了,那么您忘记了 这并不是因为您无法击败您的输入清理,NOBODY 可以。许多公司都有使用这种“注入预防”的面向世界的网站,并且认为他们的代码是安全的。当他们在推特上吹嘘自己“在十多年的在线使用中没有被黑客入侵”时,全球脚本小子需要几分钟才能将其删除。懒得去挖掘链接,但这个确切的故事发生在最近。

当您通过 ADO 发送参数化查询时,服务器会收到以下内容:

SELECT Id FROM dbo.Users WHERE UserName = ?;

请注意,查询不知道甚至不需要关心参数的类型及其周围的单引号。

请注意,无论用户输入是什么,它都是相同的语句。

请注意,参数值甚至不会涉及该查询的执行计划中的任何地方。参数单独接收,并由数据库服务器以完全安全的方式处理,由以此为生的人编写

无论您如何努力,您或任何人都无法想出任何安全措施。

如果用户输入是可执行 SQL 语句的一部分,则它不安全,句号。

不要假装做服务器的工作。只是不要。


做得对。

学习使用 ADODB CommandParameter 对象。它们有一个相当简单的 API,并且正确且一致地使用它们将击败任何字符串连接伪清理的 SQL 字符串。

这是一个详细的例子:

Const sql As String = "SELECT Id FROM dbo.Users WHERE UserName = ?;"

Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
conn.ConnectionString = "{connection string}"
conn.Open

Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.CommandType = adCommandText
cmd.CommandText = sql
cmd.ActiveConnection = conn

Dim userNameParam As ADODB.Parameter
Set userNameParam = New ADODB.Parameter
userNameParam.Type = adVarChar
userNameParam.Size = 60
userNameParam.Direction = adParamInput
userNameParam.Value = pUserName '<~ user input

cmd.Parameters.Append userNameParam

Dim result As ADODB.Recordset
Set result = cmd.Execute

MsgBox result("Id").Value
conn.Close

我说冗长,因为当您明确指定所有内容时,您就是这样做的。我个人使用我自己的 ADODB 包装类,使用它们,这段代码完全等同于上面的代码:

Const sql As String = "SELECT Id FROM dbo.Users WHERE UserName = ?;"
Dim result As Long
result = SqlCommand.QuickSelectSingleValue(sql, pUserName)

MsgBox result

如您所见,使用为您封装所有管道的适当的面向对象代码,向您的数据库服务器发送正确参数化且完全安全的查询一点也不难。

方法如下:

可以在on GitHub in the VBEX repository 找到这些修复了一些错误和其他功能的类,其中还包含大量其他有用的工具(在 GPLv3 下获得许可)。请注意,虽然我确实编写了一些代码,或者一些启发了那里的代码,但我不声称与 VBEX 存储库有任何关系。我确实将这些类的原始版本上传到了我自己的 VBTools 存储库,并在 CC-by-SA 下获得许可,任何 Stack Exchange 内容也是如此。

【讨论】:

    猜你喜欢
    • 2021-04-16
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2022-12-01
    相关资源
    最近更新 更多