我尝试使用内置的导入菜单将已打开的MS Access accdb文件中的表导入到新的accdb文件中,但是我收到了一条错误消息。 错误消息表示“admin”用户已将文件设置为无法访问的状态。 (这是我的匈牙利语翻译) 所以我无法导入任何表或查询。
我想知道,如何使用VBA代码以编程方式将accdb或accde文件移动到此无法访问的状态。
背后的原因:我想发布一个前端accde文件,它可以保护自己免受任何窃取odbc连接信息的人的攻击,比如MySQL服务器用户和密码。但是Msysobjects表可以导入到另一个访问文件中。 我可以在启动时创建表和查询,并在应用程序关闭时删除它们,但是如何在运行时阻止表和查询从中导入? 这种无法形容的状态会派上用场。 如果有其他方法阻止表导入到其他访问文件,请告诉我。
*编辑部分:* 设计视图技巧:
DoCmd.OpenForm "frmUnused",acDesign,,,,acHidden
与accdb一起使用,在编辑时锁定表导入。正如所料,不适用于accde。
连接缓存方法: 适用于查询。 固定:无论我怎么努力,用户和密码都保存在表格中。我提供了一个没有用户和密码的连接字符串,但是在将tabledef附加到集合后它出现在连接字符串中。 方法A保存了未提供的密码,方法B仅适用于手动登录。
备注:我知道将用户和密码存储在accde中的VBA中并不是最安全的选项,但是.. 1.在服务器端创建新用户并分配角色可能会非常缓慢。 (另请参阅:burocracy)2。同时将服务器凭证交给几千名用户,使社交工程更容易。 如果在文本编辑器中打开accde文件,则可以查看Const值,甚至是Private Const值。使用函数来回显值。
实际用户和密码已在下面的文本中替换。 从debug.print输出复制行之前/之后的.Connect PASS / FAIL和.Connect。
我尝试过两种变化:
答:/由Albert D. Kallal提议/ *删除所有表和查询,压缩和修复,然后重新启动应用程序。 *? tabletest:testlogon用户和pwd,然后AddOneTable(MyCon)没有。 *登录通行证 * .Connect before = ODBC; DRIVER = {MySQL ODBC 5.3 Unicode Driver}; Server = localhost; Database = mesterlista * .Connect = ODBC; DRIVER = {MySQL ODBC 5.3 Unicode Driver}; Server = localhost; Database = mesterlista; user =; password =; * >>存储用户和密码。 *修复:在.append之后,reedit。连接和重新链接。
B:/使用手动登录/ *删除所有表和查询,压缩和修复,然后重新启动应用程序。 * AddOneTable(MyCon)+ MySQL Connector / ODBC数据源配置窗口 * .Connect before = ODBC; DRIVER = {MySQL ODBC 5.3 Unicode Driver}; Server = localhost; Database = mesterlista * .Connect = ODBC; Driver = MySQL ODBC 5.3 Unicode驱动程序; SERVER = localhost; DATABASE = mesterlista; PORT = 3306 * >>注意{}在驱动程序名称中消失,PORT也出现了。 *应用程序重启 *? TestLogon(“ODBC;驱动程序= MySQL ODBC 5.3 Unicode驱动程序; SERVER = localhost; DATABASE = mesterlista; PORT = 3306”&“; user =; password =”) *是的 *表不起作用,弹出MySQL Connector / ODBC数据源配置窗口。 *? TestLogon(“ODBC;驱动程序= MySQL ODBC 5.3 Unicode驱动程序; 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 +密码。
这意味着在代码启动时您可以执行登录。你可以:
将登录嵌入VBA代码中。启动时只需要一次登录,然后所有现有的链接表都可以工作,即使链接表没有在这些连接字符串中包含用户+密码,这也可以工作。
如果您担心某人使用某种文件HEX编辑器等来解析或查看accDE文件的上下文,您可以在VBA中使用某种类型的加密或哈希代码来转换嵌入式用户+密码。
另一种简单的方法是在启动时提示用户ID +密码(询问用户id +密码)。至此,您只需执行登录即可。一旦执行了该登录,那么所有链接表都可以正常工作,并且这些链接表不需要包含UID + PASSOWRD,也不需要嵌入这些链接表中。
我不能强调,如果你这样做,不需要重新连接表格。
上面的原因和技巧是访问将缓存登录ONCE已发生合法登录。 ONCE已发生登录(连接成功),然后所有其他链接表将使用此缓存连接。
因此,我建议您删除所有链接表,然后执行登录,然后重新链接所有表,并在执行此操作时保留用户+密码。 (只记得不要在用于链接表的连接字符串中包含用户+密码。您可以使用内置表管理器执行此操作,或者您可以使用代码 - 任何一种方式都可以。
一旦您以这种方式链接,如果您启动该应用程序,表链接将不起作用,它们只能在您执行登录后工作。
这意味着,如果有人试图打开或将表链接导入另一个数据库,链接表将无法工作,因为链接表不包含用户+密码。
要执行登录,请使用以下代码:
strCon =“有效连接字符串PLUS USERID + PASSWORD”
因此,取现有连接字符串(没有userID /密码),将字符串添加到用户标识/密码,然后执行登录代码,如下所示:
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驱动程序将提示您输入用户标识+密码。 (那么你得到什么样的提示将取决于数据库供应商如何设置他们的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 / password ANYWHERE。所需要的只是使用上面的代码执行有效的登录 - 一旦完成,那么所有连接都可以正常工作。
因此,在执行登录之前或之后,链接表将在任何时间点显示或具有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 Server。但是我链接到上面的文章相当不错,示例代码是针对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登录提示的情况下单击该表。