代码之家  ›  专栏  ›  技术社区  ›  Eperbab

ms接入;如何在没有密码的情况下将其移动到不可访问状态/DSN-less表

  •  1
  • Eperbab  · 技术社区  · 7 年前

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

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

    背后的原因:我想分发一个前端accde文件,它可以防止任何人窃取odbc连接信息,如MySQL服务器用户和密码。但是Msysobjects表可以导入到另一个access文件中。
    我可以在启动时创建表和查询,并在应用程序关闭时删除它们,但如何防止;是否在运行时从中查询导入?
    这种难以接近的状态会很方便。
    如果有其他方法阻止表导入其他access文件,请告诉我。

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

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

    使用accdb,编辑时锁定表导入。与预期一样,不适用于accde。

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

    备注: 我知道存储用户;帐户中VBA中的密码不是最安全的选项,但是。。1、在服务器端创建新用户&分配角色可能会慢得令人痛苦。(另见:官僚制度)2。同时,将服务器凭据交给数千名用户也使社会工程变得更容易。
    如果在文本编辑器中打开accde文件,则可以查看常量值,甚至可以查看私有常量值。而是使用函数来回显值。

    实际用户和密码已在以下文本中替换。
    登录通过/失败和。在从调试复制行之前/之后连接。打印输出。

    我尝试了两种变体:

    A. :/Albert D.Kallal提议/
    *删除所有表和查询,压缩(&N);修复,然后重新启动应用程序。
    *?tabletest:使用user和pwd进行testlogon,然后使用AddOneTable(MyCon)而不使用。
    *登录通行证
    *。Connect before=ODBC;驱动程序={MySQL ODBC 5.3 Unicode驱动程序};服务器=本地主机;数据库=mesterlista
    *。Connect after=ODBC;驱动程序={MySQL ODBC 5.3 Unicode驱动程序};服务器=本地主机;数据库=mesterlista;用户= ;密码= ;
    *>&燃气轮机; 已存储用户和密码剑。
    * 修复:之后。追加,重新编辑。&连接;重新链接。

    B :/s用于手动登录/
    *删除所有表和查询,压缩(&N);修复,然后重新启动应用程序。
    *AddOneTable(MyCon)+MySQL连接器/ODBC数据源配置窗口
    *。Connect before=ODBC;驱动程序={MySQL ODBC 5.3 Unicode驱动程序};服务器=本地主机;数据库=mesterlista
    *。Connect after=ODBC;Driver=MySQL ODBC 5.3 Unicode驱动程序;服务器=本地主机;数据库=mesterlista;端口=3306
    *>&燃气轮机; 注意{}在驱动程序名中消失了,端口也出现了。
    *应用程序重新启动
    *?TestLogon(“ODBC;驱动程序=MySQL ODBC 5.3 Unicode驱动程序;服务器=localhost;数据库=mesterlista;端口=3306”用户= ;密码= “”)
    * 符合事实的
    *表不工作,弹出MySQL连接器/ODBC数据源配置窗口。
    *?TestLogon(“ODBC;驱动程序=MySQL ODBC 5.3 Unicode驱动程序;服务器=localhost;数据库=mesterlista;端口=3306”)+MySQL连接器/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   
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Albert D. Kallal    7 年前

    是的,你可以这样做。

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

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

    在VBA代码中嵌入登录。只需要在启动时一次性登录,然后所有现有链接表都将工作,即使链接表中的连接字符串中没有用户+密码,也可以工作。

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

    另一种简单的方法是在启动时提示用户id+密码(要求用户输入id+密码)。此时,您只需执行登录即可。一旦执行了该登录,所有链接表都将正常工作,并且这些链接表不需要包含UID+Password,也不需要嵌入这些链接表中。

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

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

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

    以这种方式链接后,如果启动应用程序,表链接将不起作用,并且只有在执行登录后才起作用。

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

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

    strCon=“有效的连接字符串加上用户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/

    但是,相同的代码和中的解释应该足够了。

    您不必在链接表中包含userid+密码,而且出于明显的安全原因,您不应该这样做。

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

    任何人都可以伪装代码,如果您在访问中遵循此方法,他们就无法获得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 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登录提示的情况下单击该表。