毫秒访问;如何在没有密码的情况下将其移动到不可访问状态/无 DSN 表

Posted

技术标签:

【中文标题】毫秒访问;如何在没有密码的情况下将其移动到不可访问状态/无 DSN 表【英文标题】:ms access; how to move it into inaccessible state / DSN-less table without password 【发布时间】:2018-04-20 17:04:39 【问题描述】:

我尝试使用内置的导入菜单将已打开的 MS Access accdb 文件中的表导入新的 accdb 文件,但收到一条错误消息。 错误消息说“管理员”用户已将文件设置为不可访问状态。 (这是我从匈牙利语翻译过来的) 所以我无法导入任何表或查询。

我想知道,如何使用 VBA 代码以编程方式将 accdb 或 accde 文件移动到这种不可访问状态。

背后的原因:我想分发一个前端 accde 文件,它可以保护自己免受任何人窃取 odbc 连接信息(如 mysql 服务器用户和密码)的侵害。但是可以将 Msysobjects 表导入到另一个访问文件中。 我可以在启动时创建表和查询,并在应用程序关闭时删除它们,但是如何防止在运行时从中导入表和查询? 这种无法访问的状态会派上用场。如果有其他方法可以阻止将表导入其他访问文件,请告诉我。

* 编辑部分:*设计视图技巧:

DoCmd.OpenForm "frmUnused",acDesign,,,,acHidden  

适用于 accdb,编辑时锁定表导入。正如预期的那样,不适用于acde。

连接缓存方式: 适用于查询。已修复:无论我多么努力,用户和密码都已保存在表格中。我提供了一个没有用户名和密码的连接字符串,但是在将 tabledef 附加到集合后,它出现在连接字符串中。 方法 A 保存了未提供的密码,方法 B 仅适用于手动登录。

备注:我知道在 accde 中的 VBA 中存储用户和密码并不是最安全的选择,但是.. 1. 在服务器端创建新用户并分配角色可能是痛苦的缓慢。 (另见:burocracy) 2. 将服务器凭证交给几千名用户也可以让社会工程变得更容易。 如果您在文本编辑器中打开 accde 文件,则可以查看 Const 值,甚至可以查看 Private Const 值。改用函数来回显值。

实际用户和密码已在下面的文本中替换。LOGON PASS/FAIL 和 .Connect before/after 行是从 debug.print 输出复制的。

我尝试了两种变体:

A:/由 Albert D. Kallal 提议 / * 删除所有表和查询,压缩和修复,然后重新启动应用程序。 * ? tabletest:使用用户和密码进行测试登录,然后使用 AddOneTable(MyCon) 没有。 * 登录通行证 * .Connect before = ODBC;DRIVER=MySQL ODBC 5.3 Unicode Driver;Server=localhost;Database=mesterlista * .Connect after = ODBC;DRIVER=MySQL ODBC 5.3 Unicode Driver;Server=localhost;Database=mesterlista;user=;password=; * >> 已存储用户名和密码。 * 修复:.append 后,重新编辑 .Connect & relink。

B:/使用手动登录/ * 删除所有表和查询,压缩和修复,然后重新启动应用程序。 * AddOneTable(MyCon) + MySQL Connector/ODBC 数据源配置窗口 * .Connect before = ODBC;DRIVER=MySQL ODBC 5.3 Unicode Driver;Server=localhost;Database=mesterlista * .Connect after = ODBC;Driver=MySQL ODBC 5.3 Unicode Driver;SERVER=localhost;DATABASE=mesterlista;PORT=3306 * >> 请注意, 在驱动程序名称中消失了,也出现了 PORT。 * 应用程序重启 * ? TestLogon("ODBC;Driver=MySQL ODBC 5.3 Unicode 驱动程序;SERVER=localhost;DATABASE=mesterlista;PORT=3306" & ";user=;password=") * 正确 * 表不工作,弹出 MySQL Connector/ODBC 数据源配置窗口。 * ? TestLogon("ODBC;Driver=MySQL ODBC 5.3 Unicode Driver;SERVER=localhost;DATABASE=mesterlista;PORT=3306") + MySQL Connector/ODBC数据源配置窗口,手动登录 * 正确 * 表工作正常。 * >> 因此,如果您希望手动登录,此方法很好,但不适用于自动登录。

用于测试的VBA代码:

Public Function tabletest()

  Dim MyConWithPassWord   As String
  Dim MyCon               As String

  MyCon = "ODBC;DRIVER=MySQL ODBC 5.3 Unicode Driver;Server=localhost;Database=mesterlista"
  MyConWithPassWord = MyCon & ";user=***;password=***"

   If TestLogon(MyConWithPassWord) = False Then
      Debug.Print "LOGON FAIL"
      Exit Function
   End If

   Debug.Print "LOGON PASS"
   AddOneTable (MyCon)

End Function

Public Function TestLogon(strCon As String) As Boolean

   On Error GoTo TestError

   Dim dbs          As DAO.Database
   Dim qdf          As DAO.QueryDef

   Set dbs = CurrentDb()
   Set qdf = dbs.CreateQueryDef("")

   qdf.Connect = strCon
   qdf.ReturnsRecords = False

   'Any VALID SQL statement that runs on server will work below.
   qdf.SQL = "SELECT 1;"
   qdf.Execute

   TestLogon = True

Exit Function

TestError:
   TestLogon = False

   Debug.Print Err.Number, Err.Description
   Debug.Print strCon

End Function


Public Function AddOneTable(strCon As String)
   On Error GoTo myerr

  Dim tdfcurrent As DAO.TableDef

  Dim LocalTable    As String      ' name of local table link
  Dim ServerTable   As String      ' name of table on SQL server

  LocalTable = "cimke"
  ServerTable = "cimke"

  Set tdfcurrent = CurrentDb.CreateTableDef(LocalTable)

  tdfcurrent.SourceTableName = ServerTable
  tdfcurrent.Connect = strCon

  Debug.Print ".Connect before = " & tdfcurrent.Connect

  CurrentDb.TableDefs.Append tdfcurrent

  CurrentDb.TableDefs.Refresh
  Debug.Print ".Connect after = " & CurrentDb.TableDefs(LocalTable).Connect

  ' fix: removing user / password from tabledef.connect:
  Set tdfcurrent = CurrentDb.TableDefs(LocalTable)
  tdfcurrent.Connect = strCon
  tdfcurrent.RefreshLink

  Debug.Print ".Connect after RELINK = " & CurrentDb.TableDefs(LocalTable).Connect



Exit Function

myerr:
   Debug.Print Err.Number, Err.Description
   Debug.Print strCon

End Function   

【问题讨论】:

见下面我的帖子。您不必在链接表中包含 uid/密码。遵循我的帖子的建议消除了在链接表中使用的连接字符串中包含 uid/密码的要求。这意味着如果有人查看链接表连接字符串,或将它们导入另一个应用程序,uid/密码将不会显示,并且不包含在此类字符串中。如果用户启动访问副本,导入链接,它们将不起作用。所以是的,您可以在这方面达到合理的安全级别。 正如我所说,这适用于其他所有人——我链接到的那篇文章是针对 MySQL 的。我的测试代码工作得很好。在这一点上,我无法确定为什么这对你不起作用,但对其他人来说,包括文章显示它是有效的。概述的方法效果很好。所以剩下的唯一问题是为什么这对你不起作用?我想如果您有任何“流浪”用户或系统 DNS,我会删除它们。我不应该因为某种原因无法让文件 DSN 工作,但“用户/系统”DSN 确实有效。但是,我们在这里没有使用 DSN。如此长的镜头将是删除 DSN。 另一个建议是尝试 3.51 驱动程序。简单的问题是其他人都没有看到您的问题或问题,并且没有其他人看到您的问题,很难提出解决方案。 还有一个建议:您没有链接任何其他表,是吗?然后你删除链接表,然后退出访问,对吗?您只想使用现有的一个链接表进行测试 - 事实上,在新启动时您没有任何链接表,对吧? 并使用全新的空白数据库执行此操作。只有那个代码,结果应该是一个链接表。 【参考方案1】:

是的,您可以这样做。

您不必在连接字符串中包含 UID + 密码。

这意味着在代码启动时您可以执行登录。您可以:

在您的 VBA 代码中嵌入登录。只需在启动时进行一次登录,然后您现有的所有链接表都将工作,即使链接表没有包含在这些连接字符串中的用户 + 密码,这也有效。

如果您担心有人使用某种文件 HEX 编辑器等来解析或查看 accDE 文件的上下文,您可以使用某种类型的加密或 VBA 中的哈希码来转换嵌入式用户 + 密码。

另一种简单的方法是在启动时提示用户 ID + 密码(向用户询问 ID + 密码)。至此,您只需执行登录即可。执行登录后,所有链接表都可以正常工作,并且这些链接表不需要包含 UID+PASSOWRD,也不需要嵌入到这些链接表中。

如果您这样做,我不能强调不需要重新链接表格。

上述原因和技巧是一旦发生合法登录,访问将缓存登录。一旦发生登录(成功连接),则所有其他链接表将使用此缓存连接。

因此,我建议您删除所有链接的表,然后执行登录,然后重新链接所有表并在执行此操作时留出用户+密码。 (请记住不要在用于链接表的连接字符串中包含用户 + 密码。您可以使用内置的表管理器执行此操作,也可以使用代码 - 任何一种方式都可以。

一旦您以这种方式链接,如果您启动应用程序,表格链接将不起作用,它们仅在您执行登录后才起作用。

这意味着如果有人尝试打开或导入表链接到另一个数据库,则链接表将不起作用,因为链接表不包含用户 + 密码。

要执行登录,请使用以下代码:

strCon = "有效连接字符串 PLUS USERID + PASSWORD"

所以取现有的连接字符串(没有用户ID/密码),将用户ID/密码添加到字符串中,然后像这样执行登录代码:

TestLogon(strCon)

执行登录的代码如下:

Function TestLogin(strCon As String) As Boolean

  On Error GoTo TestError

  Dim dbs          As DAO.Database
  Dim qdf          As DAO.QueryDef

  Set dbs = CurrentDb()
  Set qdf = dbs.CreateQueryDef("")

   qdf.connect = strCon

   qdf.ReturnsRecords = False

   'Any VALID SQL statement that runs on server will work below.

   qdf.sql = "SELECT 1 as t"
   qdf.Execute

   TestLogin = True

   Exit Function

TestError:
    TestLogin = False
    Exit Function

End Function

执行上述操作后,没有用户+密码的链接表现在可以工作了!

如果有人尝试打开或导入表链接,则不会包含用户+密码,您也不希望在用于链接表的连接字符串中包含用户+密码。

所以删除你的表格链接。执行上面的登录代码。现在重新链接表格 - 但不要选择包含用户 + 密码的选项。

如果您跳过上面的登录代码并尝试打开一个表,那么 ODBC 驱动程序会提示您输入用户 ID + 密码。 (所以你会得到什么样的提示取决于数据库供应商如何设置他们的 odbc 驱动程序来处理这个问题。

以上就是你所需要的。以下文章概述了上述代码的“想法”及其工作原理:

https://blogs.office.com/en-us/2011/04/08/power-tip-improve-the-security-of-database-connections/

但是,与上面相同的代码和解释就足够了。

您不必在链接表中包含用户 ID + 密码,出于安全考虑,您不应该这样做。

请记住,几乎所有客户端软件都需要登录,但如果您没有在代码中的任何位置嵌入 uid/密码,那么与 Access 中的链接表有关的巨大安全漏洞就会被消除。如果有人试图反汇编应用程序,获取链接表连接字符串等,他们将不会获得密码。因此,如果在启动时提示,登录,然后将这些值清空,则 uid/密码再次未嵌入到应用程序中。

任何人都可以反汇编代码,如果您在 Access 中遵循此方法,他们将无法获得 uid/密码。

如果用户导入这些链接,并且他们的 uid/密码清晰可见,那么他们将看到 uid/密码。但是,如果您在没有 uid/密码的情况下链接表,则无需将 uid/密码嵌入应用程序中的任何位置即可工作。所需要做的就是使用上述代码执行有效登录 - 一旦完成,所有连接都将正常工作。

因此,在执行登录之前或之后,链接表在任何时候都不会显示或具有 uid/密码。事实上,这甚至包括是否使用 accDB(非编译应用程序)。如果您跳入调试窗口并检查用于活动工作链接表的连接字符串,您将看到 uid/密码未包含在连接字符串中!

绝大多数客户端软件系统都必须连接到数据库,如果在代码或应用程序的任何地方都没有包含 uid/密码,那么这是一种“合理”的安全级别。

这是我使用的一些示例代码:

Sub TEst222()

  Dim MyConWithPassWord   As String
  Dim MyCon               As String

  MyCon = "ODBC;DRIVER=SQL Server;SERVER=albertkallal-pc\SQLEXPRESS;DATABASE=test3"

  MyConWithPassWord = MyCon & ";UID=TEST3;pwd=password"

  TestLogon (MyConWithPassWord)
  AddOneTable (MyCon)

End Sub

使用的TestLogon 是:

Function TestLogon(strCon As String) As Boolean

  On Error GoTo TestError

  Dim dbs          As DAO.Database
  Dim qdf          As DAO.QueryDef

  Set dbs = CurrentDb()
  Set qdf = dbs.CreateQueryDef("")

   qdf.Connect = strCon
   qdf.ReturnsRecords = False

   'Any VALID SQL statement that runs on server will work below.

   qdf.SQL = "SELECT 1"

   qdf.Execute

   TestLogon = True

Exit Function

TestError:
   TestLogon = False
   Exit Function

End Function

并添加表格链接:

Sub AddOneTable(strCon As String)

  Dim tdfcurrent As DAO.tableDef

  Dim LocalTable    As String      ' name of local table link
  Dim ServerTable   As String      ' name of table on SQL server

  LocalTable = "MyTable"
  ServerTable = "dbo.MyTable"

  Set tdfcurrent = CurrentDb.CreateTableDef(LocalTable)

  tdfcurrent.SourceTableName = ServerTable
  tdfcurrent.Connect = strCon
  CurrentDb.TableDefs.Append tdfcurrent

End Sub

我的示例代码适用于 SQL 服务器。但是我上面链接的文章相当不错,示例代码是针对 MySQL 的。

这是一个 MySQL 示例:

Dim MyConWithPassWord   As String
Dim MyCon               As String

MyCon = "ODBC;DRIVER=MySQL ODBC 3.51 Driver;Server=localhost;Database=test3"

MyConWithPassWord = MyCon & ";User=TEST3;Password=TEST3"

If TestLogon(MyConWithPassWord) = False Then
   MsgBox "LOGON FAIL"
   Exit Sub
End If

AddOneTable (MyCon)

所以你需要测试你是否真的登录了(这就是这篇文章的重点)。

如果您在重新链接期间收到提示,则表示您所拥有的内容不起作用。这里的重点是消除登录的需要。

一旦这工作。您可以启动 Access,然后双击一个表 - 将提示 ODBC 登录。但是,如果您先执行登录代码,那么您可以在没有 odbc 登录提示的情况下单击该表。

【讨论】:

我明确指定您可以在运行时动态链接表,即您正在做的事情,但这并不能提供真正的安全性,因为它会使您的连接字符串在 VBA 中可见。您可以通过多种方式对其进行混淆,但混淆并不是真正的安全性。我的回答很好。 不不不不!我的示例不建议您在运行时重新链接。您在没有 uid+密码的情况下链接表。执行上述登录(不是链接表)后,所有链接表现在都可以工作了。你不重新链接,你不包括 uid+密码。你真的能读懂我说的话吗?再次:您不会重新链接,并且您不会在链接表中包含用于连接的 uid+密码。 这与用 c++、vb.net 或其他任何东西编写应用程序没有什么不同。大多数人在链接表连接中包含 uid+密码 - 您不必这样做。再次阅读帖子:我们不会在运行时重新链接表,并且我们不会在链接表中包含 UID/密码。如果提示用户输入 uid/password 并执行上述代码,则所有链接表都可以工作,并且 uid/password 不会嵌入代码中,也不会包含在代码中。您只需向用户询问 uid/密码 - 我们不包括链接表中的 uid/密码。 执行登录后,您可以将提示用户的值清空。如果 somone 出现并导入链接表,则 uid/密码将不在这些连接字符串中。 你只问用户....这个问题意味着用户无权访问登录名或密码。这就是为什么它需要存储在代码中。当然它不在注册表中,只有 RegisterDatabase 选项才如此。如果用户有此信息,当然您不必将其存储在代码中。我知道

以上是关于毫秒访问;如何在没有密码的情况下将其移动到不可访问状态/无 DSN 表的主要内容,如果未能解决你的问题,请参考以下文章

ms访问;如何将其移入无法访问状态/无DSN表没有密码

如何在不保存 MS 访问查询的情况下将查询数据导出到 txt 文件

如何在不从 DataFrame 转换并访问它的情况下将列添加到 Dataset?

如何在没有 svndump 的情况下将 svn 迁移到另一个存储库

是否可以在没有真实设备的情况下将其应用 TVOS 发送到 iTunes 连接?

在没有 SSL 的情况下将 https 重定向到 http - IIS 7