【问题标题】:Securing your Data Layer in a C# Application在 C# 应用程序中保护数据层
【发布时间】:2010-11-15 22:09:35
【问题描述】:

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

或者它可能是应用程序和网络服务之间的连接。

您需要实现某种安全性,例如,应用程序中的连接字符串可以很容易地被逆向工程,并且可以很容易地跟踪和使用 Web 服务,并且可以出于应用程序原始目的以外的其他原因。

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

【问题讨论】:

  • 在这一点上,我、Shiraz 和 Runeborg 给出的答案组合看起来像是解决了你的问题。如果这三个中的任何一个得到赏金,我会很满足。

标签: c# security architecture


【解决方案1】:

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

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

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

对于直接访问代码,您可以使用代码访问安全和混淆。

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

用户的用户帐号被允许调用WCF服务,WCF服务运行在允许访问数据库的帐号下,用户的用户帐号对数据库没有权限。

具有 3 层的 Windows 应用程序:

  • 用户界面
  • 业务(安全检查应该向用户显示什么 UI)
  • 代理

具有 2 层的 WCF 服务:

  • 外观/业务层(安全检查是否允许用户使用此数据调用此方法)
  • 实体框架数据模型

两个层的通用 dll

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

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

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

【讨论】:

  • 这是迄今为止我得到的最接近的答案。这实际上非常适合 3 层模型:数据层 -> 逻辑 -> 表示 如果您可以将数据层保留在数据库中并在其之上有一个 LINQ to SQL 层,您可以让 WCF 服务处理 -> 表示.您能否对此进行更多评估?
  • 已编辑。如果您认为缺少任何内容,请告诉我。
  • JSYK,MS 有一个(相当新的)建议停止使用 CAS(代码访问安全):“建议我们建议不要对新代码使用 CAS。出于安全目的,您应该依赖操作系统提供了安全边界,例如在 Windows 上,您可以使用访问控制列表 (ACL)。”来源:github.com/dotnet/platform-compat/blob/master/docs/DE0002.md
【解决方案2】:

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

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

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

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

希望这种方法有助于解决您的问题。

编辑

此解决方案不允许在客户端使用 LINQ-to-SQL,只允许在中间层使用。如果这是一个破坏交易,那么这不适合你。话又说回来,在客户端可以直接访问数据库的那一刻,一扇巨大的安全门就打开了,很难关上。保护数据库本身涉及大量额外工作,因此它提供了一种基于用户的行级安全性,这种安全性自然来自三层解决方案。我通常会建议不要这样做,尽管我确实承认有时它是完全合适的。

【讨论】:

  • 这可能是我一直在等待的答案。如果你把逻辑放在你的客户端代码中,你的三层解决方案是错误的,我想在逻辑/数据层使用 LINQ to SQL 但能够将信息安全地传递给客户端并且客户端需要能够运行命令在数据库上执行,您的解决方案似乎可以解决它,谢谢!
  • 哦,您可以在客户端中添加任意数量的逻辑,只要您将其视为完全不受信任即可。这很像一个典型的 Web 表单,其中有 Javascript 在客户端检查有效性,但服务器仍然运行自己的有效性测试。无论如何,希望这对你有用。
  • 是的,我知道我可以将逻辑放在那里,我正在考虑在这种情况下被认为是“受信任”的较低级别的逻辑。再次感谢。
  • Filip,我的回答是否足以被赏金接受,或者此时是否有任何空白需要填补?
  • 我相信这里已经回答了这个问题:stackoverflow.com/questions/288070/…
【解决方案3】:

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

【讨论】:

  • 我更关注应用程序(Windows 窗体)而不是网站(asp.net)。应用程序在全球范围内可用,因此您需要具有可靠的安全性,这就是问题所在。受信任的连接不能解决这个问题?
  • 应用程序仍然容易受到各种 SQL 注入攻击,这不会解决任何问题。不过,这可能会使攻击者的生活更加艰难。
  • 好吧,我并不是说它是解决所有问题的灵丹妙药,只是指出它是一种无需硬编码用户名和密码即可保护与数据库的连接的方法。这是针对提问者的一个直接关注点。我的印象是他已经知道 SQL 注入,并且会使用适当的绑定来确保这不是问题。
【解决方案4】:

我认为这个问题没有万能的解决方案,您需要针对您遇到的特定问题分析并调整您的解决方案。

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

我能想到的保护数据的最佳方法是使用 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(不是免费的)

隔离

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

您需要确定隔离层,以便用户不会相互影响或影响整个系统,以及应用程序的使用方式。客户端需要写入数据还是只读取数据?如果他们写入,写入的数据是否以任何方式共享,您可以通过什么方式隔离/验证该数据?如果他们阅读,信息是对用户私有、对系统私有还是在用户之间共享?

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

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

您还需要正确地验证您收到的输入,以防止诸如buffer overflow hacksSQL injections 之类的黑客攻击。虽然我不知道缓冲区溢出是否是 .NET 的问题,但使用 LINQ-to-SQL 应该可以轻松预防 SQL 注入。


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

最后的建议是,如果您对安全性非常认真,您可能应该聘请安全顾问并了解银行如何设置其安全基础设施。

您仍然可以通过 LINQ to ADO.NET 将 LINQ 与 Web 服务一起使用,尽管我自己没有尝试过。

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

【讨论】:

  • 因为这个答案没有任何具体的贡献。
  • 那么您可能应该详细说明您想要实现的目标。您的应用程序将在什么情况下使用?它将如何分发以及谁可以访问它(可免费下载或受用户信任)?为什么我建议的基于帐户的安全性(不是具体的?)不起作用?你能想象到的攻击媒介是什么?你到底想防止什么?
  • 这是一个抽象的问题,但是您的回答并没有充分回答我的问题,因此答案毫无用处。想象一下在最坏的情况下使用的应用程序,每个人都可以下载,每天有数千人使用,安全性至关重要。您不能在客户端软件中存储允许直接访问数据库的可逆数据。
  • 好的,但您要阻止的是对数据库的直接访问?读访问可以吗?如果是这样,充当您控制的安全层的 Web 服务(或类似服务)应该没问题。这将如何工作取决于特定的应用程序和您存储的数据类型。为了更具体,我需要一个更具体的问题。无论如何,我无法想象在客户端存储任何此类信息的任何方式,因为应用程序必须通过某种方式将其撤消,这意味着攻击者也可以这样做。
  • 好点。我不确定您建议的身份验证是否使用会话 cookie,所以我认为值得一提,而且质询响应应该提供一些额外的安全性。我通常这样做的第一个原因是角色的额外灵活性,因为默认安全性非常好用。
【解决方案5】:

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

这样,只有网络服务器暴露给外界。您的数据库服务器舒适地位于防火墙后面,并且只能由网络服务器通过特定端口访问。

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

【讨论】:

  • 这并不能真正解决问题,它很容易跟踪应用程序访问的 ip + 端口,因此 Web 服务被暴露。我想找到一种使用方式,即在我的应用程序中使用 LINQ to SQL,但即便如此,也有一个完全安全的应用程序,其中“不可能”对数据库的连接字符串进行逆向工程。
【解决方案6】:

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

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

【讨论】:

    【解决方案7】:

    您不保护它,因为您无法保护它。首先,您无法正确隐藏凭据,即使您知道如何做到这一点,然后攻击者可以嗅探(是的,即使它已加密,您也可以在本地嗅探)或直接在线上执行 SQL 注入。

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

    此外,如果代码没有在您的系统上运行,那么对其进行多少混淆或加密也没关系,它不再是您的代码。通过逆向工程、调试、修改代码,潜在的攻击者可以将您的应用程序更改为其他内容并为所欲为。

    另外,正如其他人编写的那样,您的 Web 服务将可以直接访问。有人可以直接调用您的 Web 服务而完全忽略 GUI。

    【讨论】:

    • 好的,任何人都可以调用 web 服务,但是为什么要授予他们比标准 WinForm 客户端更多的访问权限呢?
    • 嗯,这是众所周知的,因此问题..我想找到解决问题的方法。我已经知道安全风险。
    • 这样说,“这是不可能的”,除非您信任 Windows 窗体应用程序的用户,如果您可以信任该用户,那么显然这很简单。
    【解决方案8】:

    一种安全的方法是:

    将数据层置于物理上独立的应用服务器上的 (WCF) 服务后面,并让 WinForms 客户端使用其 Windows 凭据连接到该服务。然后,服务会根据授权存储(例如 Active Directory)、数据库或它们的组合来验证用户是否可以访问服务中的各种方法。

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

    【讨论】:

    • @Steven Sudit:迟到有什么关系?
    • 那么应用程序就不会全局可用,我必须“知道”所有客户端,这在所有场景中都是不可能的。
    • @Mitch:抱歉,我的幽默感并不总是能很好地转化为这种媒体。
    • @Filip Ekberg :“那么应用程序将不会在全球范围内可用,我必须“了解”所有客户端,这在所有情况下都是不可能的。” - 我不明白你的意思。该应用程序可供其凭据授予其访问权限的所有客户端使用。
    • @Mitch:它解释这意味着客户端软件将不受他的控制,这就是为什么我们一直在谈论将客户端视为不受信任的 WCF 中间层。跨度>
    【解决方案9】:

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

    就配置文件而言,可以对文件本身进行加密或使用集成安全性,如另一张海报所述。

    【讨论】:

      【解决方案10】:

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

      HTH

      【讨论】:

        【解决方案11】:

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

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

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

        【讨论】:

          【解决方案12】:

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

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

          但是,如果您要这样做,那么您必须首先通过 SSL 保护您的 SQL 连接(请参阅technet)。与安全网络服务(也将使用 SSL)一样,这将对中间人隐藏流量的内容。

          您不能依赖连接字符串的身份验证(但使用它会为黑客增加另一层以通过),因此您必须有一个您很可能自己滚动的应用程序级别的身份验证层。

          不允许 WinForms 应用程序连接到您的操作数据库。而是创建另一个数据库并允许基于连接字符串的身份验证连接到它。不要使用这种设计执行动态 SQL,而是使用存储过程。在您的公共数据库中创建存储过程,该过程将充当您的“rpc Web 服务”以隐藏真正的 SQL(它将查询您的操作数据库并返回结果)。这将隐藏架构的操作细节并减少攻击的表面积。

          如果由于必须使用动态 SQL 而无法执行过程,则仍保留公共/可操作的数据库结构并使用视图来尽可能少地公开数据。利用数据库中的用户 ID 和任何多租户功能来预过滤视图中的数据。如果你能做到这一点,你就可以减少对连接用户数据的攻击范围。

          在不理解为什么必须允许直接 sql 连接的情况下,我只能再说一遍,你不应该这样做。您在短期内这样做的好处是以您系统的长期安全性为代价的。

          【讨论】:

            猜你喜欢
            • 2018-12-18
            • 1970-01-01
            • 1970-01-01
            • 2017-11-05
            • 1970-01-01
            • 2010-11-27
            • 1970-01-01
            • 2017-06-04
            • 1970-01-01
            相关资源
            最近更新 更多