【问题标题】:Prevent database access outside the application阻止应用程序外部的数据库访问
【发布时间】:2017-02-08 02:24:27
【问题描述】:

我们有一个使用 SQL Server 数据库运行的 MVC 应用程序。

我们正在使用 Windows 身份验证,当我们想授予用户访问我们网站的权限时,我们将他们添加到活动目录组 SEUser

我们还授予SEUser 组对我们数据库的登录和访问权限。

但问题是由于 AD 组拥有数据库权限,因此属于该组的用户不仅可以访问网站,还可以从应用程序外部连接到数据库并对其进行更改。

因此,我正在寻找任何方法来限制用户组仅当请求来自我们的应用程序而不是来自外部时才能访问数据库。

为此我想到的第一种方法是使用模拟/连接作为方法,并且只允许工作进程帐户连接到数据库,

但问题是我们也在存储过程中访问当前登录的用户信息,也使用像 SYSTEM_USERIS_MEMBER 这样的方法,它只考虑当前登录的用户,所以我们不能使用工作进程方法。

有什么方法可以针对我的特定场景实现这一点?请帮忙

【问题讨论】:

  • 问题:SQL Server 实例是否专用于您的应用程序?例如,您是否将实例与您的应用程序一起安装?

标签: sql-server asp.net-mvc database authorization


【解决方案1】:

简而言之,没有任何功能允许授权用户从一个程序(即您的中间层)而不是另一个程序(即交互式查询程序,如 SSMS)进行连接。

我能给你的最好建议是在设计你的系统时假设用户会找到一种直接连接到数据库的方法,因此尽可能限制他们的权限以避免在他们决定这样做时出现任何问题所以。

限制用户在直接连接到数据库时可以在系统上执行的操作的一个策略是使用存储过程来限制他们应该能够在数据库上执行的操作(即他们有权运行 SP,除此之外别无其他),仅通过签名通过 SP 执行来授予权限。

我还强烈建议使用审核来检测任何滥用用户权限的行为。鉴于您希望所有用户都通过您的中间层应用程序进行连接,因此检测异常活动应该相对容易。

您可能会发现一个有趣的解决方法是使用登录触发器来尝试避免通过非授权程序意外访问(AKA。避免“我不知道”的借口)。但请注意:这不是安全边界,很容易绕过,但它会帮助您让诚实的人保持诚实。

例如:

我授予对我系统上特定组的访问权限,但我想尽可能限制该组对我的应用程序:

CREATE LOGIN [myDomain\myGroup] FROM WINDOWS

因此,我将创建一个登录触发器,该触发器将检查会话中的应用程序名称,并阻止任何我尚未批准这些用户使用的应用程序。

CREATE TRIGGER connection_limit_trigger
ON ALL SERVER 
FOR LOGON  
AS  
BEGIN
IF( IS_SRVROLEMEMBER('sysadmin') != 1 )
BEGIN
    IF( IS_MEMBER('myDomain\myGroup') = 1 )
    BEGIN
        DECLARE @appName nvarchar(256)
        SELECT  @appName = program_name FROM sys.dm_exec_sessions where session_id = @@SPID
        IF( @appName != 'My approved app' )
            ROLLBACK;
    END
END
END;  

请注意,此触发器将影响我的所有用户,因此我添加了检查以避免对某些用户进行不必要的限制。

我有一个我批准的非常简单的应用程序(请参阅连接字符串上的 ApplicationName 属性):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;

namespace SampleAppSql
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlConnectionStringBuilder cnnstrbldr = new SqlConnectionStringBuilder();
            cnnstrbldr.ApplicationName = @"My approved app";
            cnnstrbldr.DataSource = @"."; //local machine
            cnnstrbldr.IntegratedSecurity = true;

            using (SqlConnection conn = new SqlConnection(cnnstrbldr.ConnectionString))
            {
                conn.Open();
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = @"SELECT @@version;";
                    string vers = (string)cmd.ExecuteScalar();
                    System.Console.WriteLine(@"SQL Server version: {0}", vers);
                }
                conn.Close();
            }
        }
    }
}

当该组的用户尝试连接 SQL Server 时,触发器会检查应用程序名称,如果不匹配,登录触发器将导致连接失败:

C:\>g:\temp\SampleAppSql.exe
SQL Server version: Microsoft SQL Server 2016 (RTM) …

C:\>sqlcmd -E -S .
Sqlcmd: Error: Microsoft ODBC Driver 13 for SQL Server : Logon failed for login 'myDomain\toto' due to trigger execution..

请注意,这种技术不是安全边界,因为授权用户可以简单地操纵应用程序名称并绕过触发器;但违规用户将无法否认她/他故意绕过您的政策。

我希望这些信息对您有所帮助。

更多详情,我推荐以下文章:

-劳尔

【讨论】:

  • 非常感谢您这么详细的回答!!我正在尝试在我的本地 sql 数据库中为此构建一个测试,但我不断收到Cannot create the trigger 'CONNECTION_AUTHORIZATION_TRIGGER', because you do not have permission. 错误,即使我已经授予了我的 Windows 登录的所有权限。有什么想法吗?
  • 您需要CONTROL SERVER 或成为sysadmin 才能创建LOGON TRIGGER。确保您是sysadmin 的成员。顺便提一句。我看到的此类错误的一个根本原因是,通过机器管理员组 (builtin\Administrators) 的成员身份授予对 sysadmin 的访问权限;并且调用者没有使用提升的提示连接到 SQL Server(因此不是完整的管理员)。尝试在您的测试框上以完全管理员身份运行 sqlcmd(右键单击 cmd 提示符,然后选择 "Run as administrator"),看看您是否通过这种方式获得了完整的系统管理员权限。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-25
  • 2015-12-02
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多