从安全的角度来看,将 ASP.NET 网站的数据库服务器用户限制为仅在存储过程上执行是否值得?

信息安全 应用安全 Web应用程序 数据库 sql服务器
2021-08-15 10:32:16

我知道显然我们必须通过用户输入验证和参数化查询来避免 sql 注入攻击。数据库服务器上已经有防火墙来限制远程连接只接受来自 Web 服务器的连接。

从安全角度来看,它是否还会增加价值,以将 ASP.NET 网站使用的实际数据库用户帐户限制为仅对他们需要的存储过程的 EXECUTE 权限?所有数据库交互都将使用这些存储过程进行。

在我看来,即使在攻击者找到访问数据库连接的方法的情况下,攻击也仅限于执行预定义的查询而没有开放式查询?

4个回答

除了使用参数化查询之外,还有两个主要(安全)原因:

  • 参数类型强制
  • 最小的特权。

最小权限原则要求您只允许任何实体(用户或应用程序)访问它需要执行定义的任务的任何内容。如果您不将 webapp 仅限于 SP,则应用程序可能会执行任何任意查询。
请注意,这在两种情况下相关:防止攻击者成功地在您的应用程序中找到漏洞(SQL 注入或任何其他可能允许他执行代码的漏洞)运行恶意 SQL 查询;并且,风险更小,正在寻找不安全、未经批准的快捷方式的开发人员(甚至是恶意开发人员)。
授予所需 SP 的 EXECUTE 权限,将阻止应用程序运行任何未预定义的查询。

Wrt 强制参数类型,虽然可以通过其他方式实现这一点,但这会将类型强制带到数据库中,但在它到达数据库服务器之前。即使用在数据库中实际定义的类型,并且不会意外跳过参数。


请注意,为了正确执行此操作并避免一些常见错误,您需要:

  1. 为 ASP.NET 应用程序定义一个特定的用户帐户
  2. 将帐户分配给自定义数据库角色
  3. 从所有其他角色中删除该帐户,例如dbo.
  4. 向您创建的自定义数据库角色授予 EXECUTE 权限
  5. 删除对 SP、表和其他 DB 对象的所有其他权限。这包括默认的“公共”角色等等。
  6. 确保自定义数据库角色没有其他权限。

绝对地。

但是你需要小心存储过程。如果可以允许将任意查询传递给它,那么您仍然停留在同一位置。

这里想到了最小特权原则,现在有点轶事。在 PostgreSQL 中(是的,我意识到这是一个 SQL Server 问题,但可能需要注意)非特权用户可能会编写一个重载的函数(相同的函数名 + 参数),这可能是恶意的询问。当特权用户运行此查询时,他们可能认为他们正在运行默认添加功能,而实际上他们正在使用恶意功能。作为一名开发人员,我知道您正在制造维护噩梦,因为总会有一个“一次性”查询需要编写。所以这里有一个问题,当您创建一个新的用户帐户时,如果这是一个预定义的查询,那么您没有为自己提供任何额外的保护。有人可能会争辩说,您实际上使情况变得更糟,因为现在您允许攻击者无限期地监视您的系统,除非您不断地监视新用户的日志文件。此外,数据会发生变化,因此UPDATE statement 是您新的最大敌人,因为它允许某人将 javascript 直接放入返回的记录中,因为我从经验中讲,每个人都相信数据库中的数据已经得到保护。

这里有一个令人讨厌的缺点——我们曾经有过这样的规则,但并不是所有的数据库请求都适合存储过程。所以发生的事情是许多开发人员在存储过程中手工构建 SQL 并在那里执行它。这导致了很多丑陋的代码和令人讨厌的潜在漏洞,因为sp_executsql至少在当时,一旦它在存储过程中,它将以 sa 级别权限运行,并且在 SQL 过程中清理输入比在现代应用程序中清理输入更丑陋语。

我们开始运行时允许对表进行 CRUD 操作,并在这件事曝光后在应用程序层强制执行参数化。