在C#应用程序中保护数据层

时间:2009-07-31 20:13:29

标签: c# security architecture

我在考虑如何在C#应用程序中保护数据层,在这种情况下,该层可以是一个LINQ to SQL模型图,它存储在Application本身,其中包含连接字符串到SQL Server数据库。

或者它可以是应用程序和Web服务之间的连接。

要么需要强制某种安全性,例如,应用程序中的连接字符串可以很容易地进行逆向工程,并且可以轻松地跟踪和使用Web服务,原因不同于应用程序的原始目的。

所以我的问题是缩短的方式:在处理Web服务和/或从Windows窗体应用程序直接连接到SQL Server时,如何解决安全问题?

12 个答案:

答案 0 :(得分:14)

在你的情况下,有两种主要的攻击可能性:

  • 窃取连接字符串,然后直接访问数据库
  • 直接在C#代码中调用方法,而不使用UI

对于连接字符串,您需要将其以加密形式存储在配置文件中。问题是winforms应用程序中需要有足够的信息才能解密并使用它。

为了直接访问代码,您可以使用代码访问安全性和模糊处理。

在您的情况下,我不会让Windows应用程序直接访问数据库。让windows app调用WCF服务,WCF服务将访问数据库。

允许用户的用户帐户调用WCF服务,WCF服务在允许访问数据库的帐户下运行,用户的用户帐户无权访问数据库。

具有3个图层的Windows应用程序:

  • UI
  • 业务(安全检查应向用户显示哪些UI)
  • 代理

2层WCF服务:

  • Facade / Business Layer(允许用户使用此数据调用此方法进行安全检查)
  • 实体框架数据模型

两个图层的常见dll

  • 合同/ WCF接口
  • 数据传输对象

有关代理,合约和DTO的信息,请参阅此视频:

http://www.dnrtv.com/default.aspx?showNum=103

答案 1 :(得分:4)

Shiraz Bhaiji走近了,但我认为他们错过了关键的一步。

是的,您希望访问数据库由中间层调解,通过WCF公开,这会强加您需要的任何业务逻辑,包括完全访问控制。此服务确实具有您要保密的连接字符串,但WinForm客户端无法访问它。

关键步骤是客户端使用用户的身份验证来获得适当的访问级别,并且永远无法联系数据库甚至无法完全控制中间层。中间层根据客户端用户所属的组授予对方法的访问权限。这意味着安全性较低的用户可以调用他们喜欢的任何方法,但他们将获得访问被拒绝的异常,或数据过滤,或任何其他适合的失败模式。用户帐户本身无法访问数据库,因此中间层可以执行任何操作。

绕过这种情况的明显方法是让客户使用具有完全访问权限的人的帐户。当然,如果他们能做到这一点,他们就已经拥有了他们想要的东西。

希望这种方法对解决您的问题很有用。

修改

此解决方案不允许客户端中的LINQ-to-SQL,只允许中间层。如果这是一个破坏者,那么这不适合你。然后,当客户端可以直接访问数据库的那一刻,一个巨大的安全门被打开,而且很难关闭。保护数据库本身需要进行大量的额外工作,以便提供基于用户的行级安全性,这种安全性自然来自三层解决方案。我一般会建议反对它,虽然我确实认为有时它是完全合适的。

答案 2 :(得分:3)

一种方法是使用Trusted Connection to SQL Server,这样就不会在代码中存储用户名/密码。

答案 3 :(得分:2)

我认为这个问题没有任何一个解决方案,你需要分析并调整你的解决方案以解决你遇到的特定问题。

据我所知,由于您的客户端是与服务器通信的“可信”部分,因此没有已知的方法在客户端安全地存储您的连接信息。无论您如何存储信息,客户端都必须能够将其反转或直接发送到服务器,这也意味着潜在的攻击者可以重复此过程。此外,任何直接与您的数据库的外部通信都可能被拦截/入侵。

我能想到的保护数据的最佳方式是使用Web服务(通过安全连接)作为控制与数据库(which you need to secure)通信的中间件,并添加逻辑以强制执行您希望的任何级别的安全性达到。如果需要,您可以基于帐户授予不同级别的访问权限。但最重要的是它只允许安全/隔离操作。

为了保护Web服务(中间件),有两个问题,即身份验证和隔离。

验证

您可以使用Steven建议的标准.NET身份验证。我通常喜欢滚动我自己的解决方案,原因有两个。首先,到目前为止,我主要是处理更复杂的用户/角色。例如,使用基于权限的角色,以便您可以检查权限而不是特定角色。

第二,它为您提供更多控制权。您可以avoid session based authentication,也可以使用challenge-response,例如使用时间戳进行挑战,并期望时间戳+密码的哈希值(用户必须在应用程序启动时输入)或其他一些创意组合回答,我确信有更好的哈希组合来回应。这也应该是双向的,以确保客户端验证从服务器获得的任何内容。

此处还有一些关于WCF授权的SO主题可能很有趣: WCF Service authorization patterns Authorization and Authentication using WCF WCF Authorization - access to operations via claims 还有a booka paper(非免费)

分离

无论您的身份验证有多安全,总有可能有人能够访问您的Web服务以获取恶意意图。据我所知,这个问题没有一个解决方案,但它取决于具体的应用程序以及如何在用户之间构建和共享数据。

您需要识别隔离层,以便用户不会相互影响或一般地影响系统,以及如何使用应用程序。客户是需要写数据还是只读?如果他们写,是以任何方式共享的书面数据,以什么方式隔离/验证数据?如果他们阅读,那么该信息对用户是私有的,对系统是私有的还是在用户之间共享?

例如,用于存储医疗日志或个人任务列表的系统将具有非常孤立的数据,您可以仅限制访问您的私人信息(可能还有您的医生/老板,具体取决于用户组)。在这种情况下,您可以隔离对特定用户的所有数据读/写,因此攻击者只能影响他自己的数据,保证其他人的安全。

如果用户之间共享数据,则需要某种方式来验证用户提供的输入。优选地,您还应该为用户提供某种信任级别,例如SO的声誉,以防止任何一次性用户尝试黑客攻击。这真的太具体了,无法给出任何好的建议。

您还需要验证您收到的输入,以防止buffer overflow hacksSQL injections等攻击。尽管我不知道缓冲区溢出是否是.NET的问题,但使用LINQ-to-SQL可以很容易地防止SQL注入。


总而言之,没有100%保证保护数据的方式,您应该定期备份数据(与数据库分开),以防您受到损害,也可能是事务日志。

作为最后的建议,如果你真的认真对待安全问题,你应该雇用一名安全顾问,并查看银行如何建立他们的安全基础设施。

此外,您仍然可以通过LINQ to ADO.NET使用LINQ和webservices,但我自己没有尝试过。

此链接可能更多解释How to move from LINQ to SQL to “LINQ to WCF”?

答案 4 :(得分:0)

在安全性非常重要的情况下,例如,当您存储信用卡信息时,您通常会希望数据存储库和网络服务器位于单独的盒子上,防火墙之间以及两者都被IP安全锁定。

这样,只有网络服务器才会暴露给外界。您的数据库服务器位于防火墙后面,只能通过某个端口由Web服务器访问。

您可能还会考虑对Web服务进行SSL加密,并仅公开HTTPS端点。

答案 5 :(得分:0)

我在这里并不完全清楚。如果winforms应用程序调用webservice,则使用适当的模型进行相互信任的身份验证。这可以基于客户端和服务器证书或带有客户端证书的SSL甚至Net.Tcp(如果您都是.Net)。然而,只有受信任的客户端可以进行通信,才会公开Web服务。然后,web服务可以留在DMZ和DB后面的另一个DMZ。使用适当的防火墙规则和webservice和SQL之间的IPSec连接是一种选择。

对于许多winforms应用程序直接连接到SQL服务器,挑战很多。与数据库的连接必须经过身份验证和加密。在任何情况下,您的SQL服务器都将被公开,我不会推荐这样的模型。

答案 6 :(得分:0)

你没有保护它因为你无法保护它。首先,你无法正确隐藏凭据,即使你弄清楚如何做到这一点,然后攻击者可以嗅(是,即使它是加密的,你可以在本地嗅探)或直接在线上进行SQL注入。

您需要以安全的方式编写所有Web服务调用,而不需要传输原始SQL查询或直接SQL Server连接。

如果代码没有运行你的系统,那么对它进行多少混淆或加密并不重要,这不再是你的代码了。通过逆向工程,调试,修改代码,潜在的攻击者可以将您的应用程序更改为其他内容并执行他们想要的任何操作。

此外,正如其他人所写,您的网络服务将开放直接访问。有人可以直接拨打您的网络服务,完全忽略GUI。

答案 7 :(得分:0)

安全方法是:

将数据层放在物理上独立的Application Server上的(WCF)服务后面,让WinForms客户端使用其Windows凭据连接到该服务。然后,该服务验证用户是否可以基于授权存储(例如Active Directory)和数据库或其组合访问服务中的各种方法。

然后,数据服务可以使用单个池标识连接到数据库。

答案 8 :(得分:0)

Web服务的一种常见方法是通过Web方法签名传递加密的用户名和密码,以验证尝试调用Web方法的用户确实有权这样做。

就配置文件而言,可以加密文件本身或使用集成安全性作为另一张提到的海报。

答案 9 :(得分:0)

很难提供准确的答案,因为我不确定您要解决的具体问题是什么,以及哪个是确保系统安全的关键驱动因素。
但是,在过去我使用过WinForms - >利用WSE进行WebService安全通信 我们使用了X509证书和WS-Security。这具有提供End To End Security而不是依赖标准SSL传输的明显优势 然而,这本身并不能解决用户身份验证本身等问题,在这种情况下Mitch Wheat's answer似乎是一个很好的解决方案 但是,您的用户身份验证模型将取决于这是否是公共分布式应用程序,工具的用户数量是大还是小等。
对于少数用户或费用不成问题,您可以通过设置RSA SecurID等来实施RADIUS server身份验证。这样做的优点在于每个RSA密钥都是唯一的并且与该用户相关联(尽管您永远不能阻止用户提供其凭据和PIN)

HTH

答案 10 :(得分:0)

答案很简单,保护sql字符串很简单。 从不在客户端直接连接SQL。

在经过散列的公用私钥对(http://msdn.microsoft.com/en-us/library/6f05ezxy.aspx)中进行身份验证后,只接受格式良好,架构验证的xml序列化对象作为程序的入口,这是您程序中附带的公钥证书,因此有人窃听不会发现密码。

另外,请注意DDOS攻击。测量每个客户端公开的每个Web服务的使用情况,如果使用超过给定限制,则阻止来自用户和用户IP的所有传入连接。

答案 11 :(得分:0)

如果我正确理解OP,不可变设计特性是直接连接到可公开访问的SQL Server的WinForms客户端?

几乎所有回复的人都基本上说“不要这样做,而是使用网络服务”。这是个好建议。即使ws被黑客入侵,它也只能做它设计的事情。因此,RPC WS只能执行已编写的方法,而黑客SQL Server连接则允许任意SQL执行。此外,我认为您会发现设计良好的Web服务会更高效。

但是,如果您要执行此操作,那么必须通过SSL保护您的SQL连接(请参阅technet)作为开始。与安全的Web服务(也使用SSL)一样,这将隐藏中间人员的流量内容。

您不能依赖连接字符串的身份验证(但使用它会为黑客添加另一层以便通过),因此您必须拥有一个您最有可能自行推出的应用程序级身份验证层。

不要让WinForms应用程序连接到您的操作数据库。改为创建另一个数据库,并允许基于连接字符串的auth连接到它。不要使用此设计执行动态SQL,而是使用存储过程。在公共数据库中创建存储过程,作为“rpc Web服务”来隐藏真实的SQL(它将查询操作数据库并返回结果)。这将隐藏模式的操作细节并减少表面攻击区域。

如果因为必须使用动态SQL而无法解决问题,那么仍然保留公共/可操作的数据库结构并使用视图来尽可能少地公开数据。利用用户ID和数据库中的任何多租户功能来预过滤视图中的数据。如果可以这样做,则可以将攻击的表面区域减少到连接用户的数据。

如果不理解为什么必须允许直接sql连接,我只能再次说你不应该这样做。您在短期内获得的收益是以系统的长期安全为代价的。