代码之家  ›  专栏  ›  技术社区  ›  Sam

请求临时登录的安全性

  •  1
  • Sam  · 技术社区  · 16 年前

    我需要建立一个允许开发人员请求数据库紧急ID的系统。他们将被分配到一个名为“分析师”的角色,该角色将为他们提供一个下拉框,其中包含他们可以访问的数据库。他们将提交请求,并将生成一个临时的SQL登录并显示在屏幕上。登录名将具有一些提升的权限。登录将在12小时后删除。

    我已经在ASP.NET上以SA的身份运行了整个过程,但现在我正在修改过程,以便使用应用程序连接字符串中的SQL登录来工作。

    我试过一些方法让它工作,但遇到了障碍。

    这是我的程序,它真正起作用。

        USE [SQLEmergencyLoginRequest]
    GO
    /****** Object:  StoredProcedure [dbo].[SQLELR_Login_CREATE]    Script Date: 12/08/2009 14:48:29 ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER  PROCEDURE [dbo].[SQLELR_Login_CREATE] 
    @SERVER VARCHAR(50),
    @DATABASE VARCHAR(50),
    @NTLOGIN VARCHAR(50),
    @IR INT,
    @LOGIN VARCHAR(50) OUTPUT,
    @PWD VARCHAR(20) OUTPUT,
    @NotifyDBA INT 
    WITH EXECUTE AS OWNER 
    AS
    /*
    Emergency_Access_Login_CREATE:  Create Login/PWD, Create User, Create Role, Add User to Role, return Login/PWD.
    */
    DECLARE @Random_Login_Extension VARCHAR(20)
    DECLARE @sql VARCHAR(1000)
    
    SET @Database = QUOTENAME(@Database);
    
    
    BEGIN TRANSACTION
    
    --CREATE LOGIN/PWD
    EXEC dbo.random_password @Random_Login_Extension OUTPUT;
    EXEC dbo.random_password @PWD OUTPUT;
    
    SET @LOGIN = 'Emergency_Login_' + @Random_Login_Extension;
    
    SET @sql= 'CREATE LOGIN [' + @LOGIN + ']' +
    'WITH PASSWORD= ''' + @PWD + ''', DEFAULT_DATABASE=[master], ' +
    'CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF';
    
    EXEC(@sql);
    
    --CREATE USER
    DECLARE @User_Cmd VARCHAR(1000);
    
    SET @User_Cmd = 'USE ' + @DATABASE + ';' +
    
    'CREATE USER [' + @LOGIN + '] FOR LOGIN [' + @LOGIN + '];' +
    'EXEC sp_addrolemember N''db_datareader'',''' + @LOGIN + ''';' +
    'EXEC sp_addrolemember N''db_datawriter'',''' + @LOGIN + ''';' +
    'EXEC sp_addrolemember N''db_ddladmin'',''' + @LOGIN + ''';';
    
    EXEC (@User_Cmd);
    
    INSERT INTO dbo.SQLELR_Emergency_Logins
               ([CreationTime]
               ,[NTLogin]
               ,[IR]
               ,[SERVER]
               ,[DATABASE]
               ,SQLLoginCreated)
         VALUES
               (GETDATE()
               ,@NTLOGIN
               ,@IR
               ,@SERVER
               ,@DATABASE
               ,@LOGIN)
    
    
    DECLARE @MYBODY VARCHAR(500)
    SET @MYBODY = @NTLOGIN + ' has created a temporary login in the ' + @Database + ' Database.  The login name is ' + @LOGIN;
    
    DECLARE @MYSUBJECT VARCHAR(500) 
    SET @MYSUBJECT = 'Emergency Login Creation ON server ' + @@SERVERNAME;
    
    IF @NotifyDBA = 1
    BEGIN 
        EXEC msdb.dbo.sp_notify_operator
           @profile_name = 'SQLDBA',
           @name = 'SQLDBA',
           @subject = @MYSUBJECT,
           @body = @MYBODY;
    END 
    
    COMMIT TRANSACTION
    

    我不希望应用程序帐户在每个数据库中都具有高度特权,因此我创建了另一个帐户,该帐户将进入每个数据库并 db_owner . 明显地 sp_addrolemember 使用固定数据库角色需要一个数据库所有者才能工作,这就是为什么acct是 数据库所有者 . 我更喜欢安全管理,但似乎不可能。

    回到问题上来-将execute as与动态代码一起使用不起作用。

    只有在创建用户的每个数据库中创建一个存储过程,才能实现这一点吗?

    我们这样做是因为我们想降低这台服务器的安全性,并从开发人员那里夺走db_所有者,这已经是多年来的惯例了。创建这个机制将满足他们唯一剩下的关于无法访问的抱怨。他们担心我们不会回答一页,他们将无法解决问题,所以这将解决这个问题。

    当然,任何关于这里安全漏洞的建议也会受到赞赏。

    1 回复  |  直到 16 年前
        1
  •  1
  •   Remus Rusanu    16 年前

    工作过程中的execute as子句将您放入“execute as”框架中,请参见 Extending Database Impersonation by Using EXECUTE AS .因为从过程开始执行是 数据库主体 ,将只信任数据库中的“执行为”上下文。

    有两种解决方法,500磅的大锤 ALTER DATABASE [SQLEmergencyLoginRequest] SET TRUSTWORTHY ON 或代码签名的外科精确工具,参见 Call a procedure in another database from an activated procedure 例如。我强烈推荐代码签名方法:

    • 在sqleemergencyloginRequest中创建证书
    • 签署程序
    • 删除证书的私钥以防止将来用于签名
    • 导出证书
    • 在master中导入证书
    • 创建从证书派生的登录名
    • 向证书派生的登录授予服务器上的身份验证
    • 将该过程所需的所有其他特权授予此派生登录

    这将确保该过程在任何数据库中都具有完成其工作所需的所有特权。每次更改签名过程时,都必须重新执行整个签名过程。