SQL 服务器权限链

SQL Server Permission Chaining

我有以下问题:

我有两个不同的数据库,db1 和 db2。我有一个将数据加载到 db2 或 db3 中的应用程序。 db1 有几个表,应用程序使用这些表来确定行为,包括应用程序应将数据加载到哪个数据库。

用户需要对 db1 具有写入权限才能操作该应用程序(有一个控制台应用程序写入 db1 中的表,使用 windows 身份验证进行操作)。

除了一些预先确定的操作外,用户不应该拥有对 db2 和 db3 的 DML 权限。我们授予 AD 组数据库角色以从组织角度控制访问。具体来说,我正在尝试在 db1 中构建一个存储过程,操作员可以使用该存储过程通过适当的日志记录来反转加载到 db2 或 db3 的数据。

我正在尝试使用 create proc ... execute as owner 来完成此操作,但是当我尝试访问 db2/db3 中的表时它似乎不起作用(我认为“以所有者身份执行”在数据库级用户而不是服务器级登录上运行?)。以下导致权限错误,指出所有者(我自己)没有 db2/db3.

的权限
use db1
go

create proc dbo.wrapper @recordid int 
as begin 
/*
  capturing user
*/
declare @usr varchar(255) = SUSER_SNAME()
exec dbo.inner @usr , @recordid 
end 

use db1
go

create proc dbo.inner @usr varchar(255), @recordid int
with execute as owner 
as begin 
    /*
       logic to determine whether to update db2 or db3 goes here
    */
    insert db2.rolled_back 
    select * , @usr from db2.transactions where id = @recordid 

    delete from db2.transactions where id = @recordid 

    insert db3.rolled_back 
    select * , @usr from db3.transactions where id = @recordid 

    delete from db3.transactions where id = @recordid 

end

有没有办法让它工作?我听说证书签名可以做到这一点,有没有人有使用证书用户的经验。我们的 DBA 宁愿不必维护证书,所以如果有一种方法可以在没有证书的情况下使它工作,那将是最好的。

任何建议都会有所帮助。

谢谢!

我将在这里介绍跨数据库链接方面的内容。请注意,使用此方法时肯定会有安全考虑。例如,有权在一个数据库中创建对象的人可以通过所有者访问另一个数据库中的数据,而他们自己对另一个数据库没有 no 访问权限。但是,安全问题超出了此答案的范围。

首先,让我们创建几个测试数据库。

USE master;
GO

CREATE DATABASE Chain1;
CREATE DATABASE Chain2;

现在我要CREATE一个LOGIN,它被禁用并成为这两个数据库的所有者。具有相同所有者的数据库很重要,否则链接将不起作用。

CREATE LOGIN ChainerOwner WITH PASSWORD = N'SomeSecurePassword123';

ALTER LOGIN ChainerOwner DISABLE;
GO
ALTER AUTHORIZATION ON DATABASE::Chain1 TO ChainerOwner;
ALTER AUTHORIZATION ON DATABASE::Chain2 TO ChainerOwner;

我还将创建一个 LOGIN,我们将用它来测试:

CREATE LOGIN SomeUser WITH PASSWORD = N'SomeSecurePassword123';

太好了,现在我可以创建一些对象了; Chain1 中的 table,Chain2 中的 PROCEDURE 访问 TABLE,两个数据库中的 USER 用于 SomeUser .在 Chain1 中,USER 将被授予 权限,而在 Chain2 中,用户将被授予 EXECUTE PROCEDURE:

USE Chain1;
GO
CREATE TABLE dbo.SomeTable (I int IDENTITY,
                            S varchar(10));
INSERT INTO dbo.SomeTable (S)
VALUES ('abc'),
       ('xyz');
GO
CREATE USER SomeUser FOR LOGIN SomeUser;
GO
USE Chain2;
GO
CREATE PROC dbo.CrossDBProc @I int AS
BEGIN
    SELECT I,
           S
    FROM Chain1.dbo.SomeTable
    WHERE I = @I;
END;
GO
CREATE USER SomeUser FOR LOGIN SomeUser;
GO
GRANT EXECUTE ON dbo.CrossDBProc TO SomeUser;
GO

太好了,所有对象都已创建,现在让我们尝试 EXECUTE PROCEDURE:

EXECUTE AS LOGIN = 'SomeUser';
GO
EXEC dbo.CrossDBProc 1; --This fails
GO
REVERT;
GO

这失败了,出现权限错误:

The SELECT permission was denied on the object 'SomeTable', database 'Chain1', schema 'dbo'.

这是预料之中的,因为没有所有权链。让我们现在启用它。

USE master;
GO

ALTER DATABASE Chain1 SET DB_CHAINING ON;
ALTER DATABASE Chain2 SET DB_CHAINING ON;

现在,如果我再试一次,同样的 SQL 有效:

USE Chain2;
GO
EXECUTE AS LOGIN = 'SomeUser';
GO
EXEC dbo.CrossDBProc 1; --This now works
GO
REVERT;
GO

这样就成功了returns结果集

I S
1 abc

所以,是的,您可以链接跨数据库,但它需要一些设置,并且(再次)有您需要考虑的安全注意事项。

清理:

USE master;
GO
DROP DATABASE Chain1;
DROP DATABASE Chain2;
GO
DROP LOGIN ChainerOwner;
DROP LOGIN SomeUser;