C# 如何安全地配置数据库连接

C# 如何安全地配置数据库连接,c#,database,nhibernate,connection-string,app-config,C#,Database,Nhibernate,Connection String,App Config,相似但不相同: 大家好,我有一个C#WinForms应用程序连接到数据库服务器。数据库连接字符串(包括通用用户/密码)放置在NHibernate配置文件中,该文件与exe文件位于同一目录中 现在我遇到了这个问题:运行应用程序的用户不应该知道普通数据库用户的用户名/密码,因为我不希望他直接在数据库中搜索 或者,我可以硬编码连接字符串,这是错误的,因为如果数据库被移动,或者如果管理员想要在dev/test/prod环境之间切换,则必须能够更改连接字符串 长期以来,我发现了三种可能性: 第一个

相似但不相同:

大家好,我有一个C#WinForms应用程序连接到数据库服务器。数据库连接字符串(包括通用用户/密码)放置在NHibernate配置文件中,该文件与exe文件位于同一目录中

现在我遇到了这个问题:运行应用程序的用户不应该知道普通数据库用户的用户名/密码,因为我不希望他直接在数据库中搜索

或者,我可以硬编码连接字符串,这是错误的,因为如果数据库被移动,或者如果管理员想要在dev/test/prod环境之间切换,则必须能够更改连接字符串

长期以来,我发现了三种可能性:

  • 第一个参考问题的答案通常是使文件仅对运行应用程序的用户可读

    但在我的情况下,这还不够(运行应用程序的用户是个人。数据库用户/通行证是通用的,个人甚至不应该访问)

  • 第一个答案还建议在将连接数据写入文件之前对其进行加密

    使用这种方法,管理员无法再配置连接字符串,因为他无法手动对其进行加密

  • 第二个参考问题为这种情况提供了一种方法,但似乎非常复杂

  • 我向您提出的问题:

  • 这是一个非常普遍的问题,所以没有任何普遍的“如何做”的方式,某种程度上是一种“设计模式”吗

  • 在.NET的配置基础设施中是否有一些支持

  • (可选,可能超出范围)我可以轻松地将其与NHibernate配置机制结合起来吗

  • 更新:

    作为对第一个答案的回应:我希望直接连接到数据库而不使用web服务的原因有很多:

    • (N) Hibernate只能用于数据库,不能用于Web服务(对吗?)
    • 我们计划提供离线功能,即如果数据库或网络关闭,用户可以继续工作。为了管理这一点,我考虑使用一个本地的进程内数据库,例如SQL Server Compact,并在服务器数据库再次启动时使用MS Sync framework将其与服务器数据库同步

    考虑到这一点,您还有其他想法吗?

    首先,让不受信任的用户连接到数据库通常不是一个好主意。很多事情都会出错。将web服务置于两者之间

    如果你一定要这么做,那么即使他们得到用户名和密码,也不要在意。限制他们在数据库中的权限,以便他们只能执行几个具有内置安全检查的存储过程


    无论您做什么,都不能将特权用户的用户名/密码提供给不受信任的人。这只是自找麻烦。无论您如何将凭证隐藏在二进制文件或其他文件中的加密字符串中,总有办法找到它们。当然,是否有人真的会这么做取决于你的数据有多有趣,但默默地希望调试器的人会让你一个人呆着不是一个很好的安全措施。

    我认为这很难做到:就像你不想让stackoverflow的用户知道他的密码一样。 用户可以随时跟踪其网络流量并查看用户/密码(您可以使用编码,但我认为它仍然不能100%确定)


    我认为您应该在用户和数据库之间添加一个Web服务,每个用户都有一个唯一的id。

    这就是为什么数据库桌面应用程序很糟糕。没有好办法把它切成薄片。最好的选择是使用存储过程或web服务。基本上,另一层可以被锁定并控制对数据库的访问。

    实际上,WebService方法(在其他一些答案中提到)意味着您将NHibernate及其逻辑移动到web服务。然后,Web服务使用Web服务的方法公开应用程序可用的db功能

    数据库实际上只有一个用户,即WebService使用的用户,如果您希望应用程序用户具有不同的db权限,则可以从WebService层将其抽象出来

    最后,WinForms应用程序只知道通过WebService的方法请求数据的WebService的位置,您可以在这两个端点之间应用任何必需的安全措施

    对于离线功能,这一切归结为制定一种安全的方法将数据持久化到本地存储,并通过WebService提供一种同步方法

    实际上,我使用了一个与DB通信的Web服务和一个只与Web服务通信的WinForm应用程序(.NET Compact Framework),如果没有蜂窝网络覆盖,它将序列化对存储卡的更改(数据并不重要,因此对于我的案例而言,未采取模糊/淫秽安全措施)

    按要求更新一个小例子(我确实觉得奇怪,但要求提供一个关于这个的例子)

    您已经在ASP.NET WebService应用程序类型的项目中设置了域类和nhibernate配置以及(例如)存储库内容。为了简单起见,我只准备一个web服务类
    Foo
    (在Foo.asmx.cs中)和一个
    Bar
    域类

    因此,您可以得到以下结果(实际实现情况各不相同):

    我们将DAO行为抽象出来,或者直接使用nhsession,作为webmethod公开

    现在,从WinForm应用程序开始,您需要做的就是添加一个WebReference,它对配置进行所有必要的更改,但是
    namespace FWS
    {
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
        // [System.Web.Script.Services.ScriptService]
        public class FooService : WebService
        {
            private readonly ILog errorLogger = LogManager.GetLogger("ErrorRollingLogFileAppender");
            private readonly IDaoFactory daoFactory = new DaoFactory();
            private readonly ISession nhSession =  HibernateSessionManager.Instance.GetSession();
        }
    
        [WebMethod]
        public Bar[] GetFavoriteBars(string someParam, int? onceMore){
            return daoFactory.GetBarDao().GetFavoriteBars(someParam, onceMore); //returns a Bar[]
        }
    }
    
    namespace WinFormK
    {
        public class KForm(): System.Windows.Forms.Form
        {
            public void Do()
            {
                var service = new FWS.FooService();
                string filePath = "C:\\temp\FooData.xml";
                Bar[] fetched = service.GetFavoriteBars("yes!", null);
    
                //lets write this to local storage
                var frosties = new XmlSerializer(typeof(Bar));
                TextReader reader = new StreamReader(filePath);
    
                try
                {
                    var persisted = (T)frosties.Deserialize(reader);
                }
                catch(InvalidOperationException)
                {
                    //spock, do something
                }
                finally
                {
                    reader.Close();
                    reader.Dispose();
                }
            }
        }
    }