如何在VBA中安全地存储连接字符串详情

15
我有一个Excel模板,在VBA代码中硬编码了用于连接到Access表并保存/检索数据的Ms Access MDB路径。
我将MS Access数据库迁移到了带有集成身份验证的SQL Server上,供Excel模板用户使用。
我的问题是,存储SQL Server DB连接字符串并在Excel 2007 VBA中检索它以保存和检索数据的推荐方法/最佳实践是什么?
过去,我已经采取了以下做法:
1. 使用注册表键设置连接字符串。然后在VBA中编写一个函数,读取注册表键并返回连接字符串。 2. 在Excel模板中创建一个“Settings”隐藏工作表,带有命名单元格用于连接字符串。通过访问该命名范围,在VBA中读取连接字符串。 3. 使用配套Excel模板的.INI txt文件。(这不理想,我想避免依赖于外部文件)
我不喜欢#1,因为我尽可能要避免读写注册表。#2感觉还可以,虽然我不确定是否有更好、更“清洁”的方法来解决这个问题。
你有什么想法吗?

请查看我对这个帖子的回答:https://dev59.com/DkvSa4cB1Zd3GeqPbRT5#2018970 - MikeD
@Remou. 谢谢。 @MikeD. 谢谢,我查看了那个。虽然它使用了注册表,但我正试图避免这样做。因为当使用注册表设置时,解决生产问题将变成一场噩梦(因为它将是用户机器特定的设置)... - Shiva
我发现注册表是一个很好的地方,但这需要为每个用户进行额外的设置。我能理解你想要避免这样做的原因。 - RubberDuck
2个回答

32

这是我安全存储连接字符串凭据的方法

下载并安装Visual Studio Express 2012 for Windows (免费)

以管理员身份打开并创建一个新项目。选择Visual C#,然后选择类库并将其重命名为HiddenConnectionString

enter image description here

在“解决方案资源管理器”中,将Class1.cs重命名为MyServer.cs

enter image description here

在“解决方案资源管理器”中右键单击您的MyConnection项目,然后选择添加引用
在搜索框中输入activeX,并选中Microsoft ActiveX Data Objects 6.1 Library

enter image description here

将以下代码复制并粘贴到MyServer.cs文件中,完全替换文件中的任何内容。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using ADODB;

namespace HiddenConnectionString
{
    [InterfaceType(ComInterfaceType.InterfaceIsDual),
    Guid("2FCEF713-CD2E-4ACB-A9CE-E57E7F51E72E")]
    public interface IMyServer
    {
        Connection GetConnection();
        void Shutdown();
    }

    [ClassInterface(ClassInterfaceType.None)]
    [Guid("57BBEC44-C6E6-4E14-989A-B6DB7CF6FBEB")]
    public class MyServer : IMyServer
    {
        private Connection cn;

        private string cnStr = "Provider=SQLOLEDB; Data Source=SERVER\\INSTANCE; Initial Catalog=default_catalog; User ID=your_username; Password=your_password";

        public MyServer()
        {
        }

        public Connection GetConnection()
        {
            cn = new Connection();
            cn.ConnectionString = cnStr;
            cn.Open();
            return cn;
        }

        public void Shutdown()
        {
            cn.Close();
        }
    }
}

在代码中找到cnStr变量并更新连接字符串的详细信息。

解决方案资源管理器中右键单击*HiddenConnectionString*解决方案,然后选择属性。

单击左侧的应用程序选项卡,然后单击程序集信息并选中使程序集可由COM调用

enter image description here

点击左侧菜单中的*生成*,并选中注册COM互操作性

enter image description here

注意:如果您正在为64位Office开发,则确保在“生成”菜单上更改平台目标x64!这对于64位Office COM库是强制性的,以避免任何与ActiveX相关的错误。
在解决方案资源管理器中右键单击HiddenConnectionString,然后从菜单中选择Build
如果一切顺利,那么你的HiddenConnectionString.dllHiddenConnectionString.tlb应该已经成功生成。现在前往此路径。
C:\Users\administrator\Documents\Visual Studio 2012\Projects\HiddenConnectionString\HiddenConnectionString\bin\Debug

然后你应该能看到你的文件。

enter image description here


现在打开Excel并进入VBE。 点击工具并选择引用

点击浏览按钮,然后导航到HiddenConnectionString.tlb

此外,还要添加对Microsoft ActiveX Object 6.1 Library的引用-这样您就可以使用ADODB库。

enter image description here

现在在“项目资源管理器”窗口的任何位置右键单击,并插入一个新的“模块”。
将下面的代码复制并粘贴到其中。
Option Explicit

Sub Main()

    Dim myCn As MyServer
    Set myCn = New MyServer

    Dim rs As ADODB.Recordset
    Set rs = New ADODB.Recordset

    rs.Open "Select * from [TABLE_NAME]", myCn.GetConnection

    Range("A1").CopyFromRecordset rs

    rs.Close
    myCn.Shutdown

    Set rs = Nothing
    Set myCn = Nothing

    Columns.AutoFit

End Sub

在你的数据库中,用一个实际的表名替换[TABLE_NAME]

按下F5或点击功能区上的绿色播放按钮。

enter image description here

如果一切顺利,您现在应该在电子表格上看到返回的表格。
我的示例:

enter image description here


正如您所看到的。将自己的COM库引用添加到编译的.dll中并将登录凭据和其他敏感数据存储在其中可以保护您的数据(连接字符串)。从*.dll文件反编译获取任何有意义的信息非常困难。有各种编码技术可以进一步保护您的*.dll,但我现在不打算详细介绍。这本身就实现了您要求的内容。

myCn.GetConnection返回初始化在引用的COM库内的ADODB.Connection对象。没有Excel用户会看到连接字符串或敏感数据(实际上其他人也不会)。

如果您拥有对SQL Server实例具有不同特权的用户,允许人们登录可能不是一个坏主意,您可以修改C#代码以从VBA接受参数,即登录、密码、初始目录、要执行的查询等。


注意:C#代码和VBA中没有添加错误处理。如果您计划使用我上面描述的技术,我强烈建议您进行错误处理。

1
我也在我的博客上发布了这个答案。
  • 已收藏!感谢您在这些帖子中做出的出色贡献。
- tbur
2
@mehow 感谢您详细的回答。正如您所看到的,这已经是3年前的事了,我不再从事那个项目或客户,但我仍然接受了您的答案。看起来它会起作用。 - Shiva
2
@Shiva 谢谢。我决定还是回答这个问题,因为在某个时间点我自己也找不到答案。希望它能对其他人有所帮助 :) - user2140173
1
@Yiping 这取决于您如何设置整个环境。通常,您可能只允许某些域用户能够与您的SQL / 任何服务器建立连接,不是吗?如果您使用的是Windows身份验证/或每个用户身份验证,您可能甚至不需要隐藏您的连接字符串,因为您不需要用户名和密码... - user2140173
2
抱歉,这仍然只是安全的幻觉。事实上,这使得更容易破解您的数据库,因为您可以引用您的COM对象并使用它来获取自己的原始连接。 - Comintern
显示剩余4条评论

2

把它存储在CustomDocumentProperties下怎么样?

注意:我不确定,基于给定模板的工作簿是否会继承在模板中使用CustomDocumentProperties定义的属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接