AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 158609
Accepted
BeginnerDBA
BeginnerDBA
Asked: 2016-12-20 11:31:50 +0800 CST2016-12-20 11:31:50 +0800 CST 2016-12-20 11:31:50 +0800 CST

为 SQL Server 中的存储过程授予特殊权限

  • 772

我有一个名为数据库B的受限数据库(包含机密数据),只有几个用户可以访问它。但是,我需要从B中的几个表中选择一些数据,以供请求它的用户使用。请求数据的用户不会作为数据库用户添加到数据库B,因为他们无权访问。但是,这些用户可以访问数据库A(他们被添加为 DB A的 DB 用户)。有没有办法让存储过程访问机密数据库 ( B ),以便运行 SP 的任何用户都可以获得他们请求的数据?如果是这样,如何?我研究过这是可能的,但没有提到如何。

注意:通过 IS 包将所需数据从数据库B移动到A不是一个选项(假设需要实时访问)。我也考虑过使用视图(但又一次,如何?如果您无权访问基表,您也将无法通过视图访问数据)。 在此处输入图像描述

sql-server sql-server-2012
  • 3 3 个回答
  • 1224 Views

3 个回答

  • Voted
  1. Best Answer
    Solomon Rutzky
    2016-12-20T15:21:15+08:002016-12-20T15:21:15+08:00

    这很容易实现(包括处理多个数据库和动态 SQL),无需任何模拟(IMPERSONATE许可)、跨数据库所有权链接(服务器/实例或数据库设置)或TRUSTWORTHY(数据库设置)。一般来说,你需要做的是:

    1. 在数据库 A 中创建证书
    2. 使用ADD SIGNATURE对数据库 A 中的存储过程进行签名
    3. 在数据库 B 中创建相同的证书
    4. 根据该证书在数据库 B 中创建用户
    5. 为新用户分配访问所需表所需的权限

    例子:

    清理

    USE [master];
    GO
    IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseA')
    BEGIN
        PRINT 'Dropping [DatabaseA] DB...';
        ALTER DATABASE [DatabaseA] SET OFFLINE WITH ROLLBACK IMMEDIATE;
        ALTER DATABASE [DatabaseA] SET ONLINE;
        DROP DATABASE [DatabaseA];
    END;
    
    IF EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = N'DatabaseB')
    BEGIN
        PRINT 'Dropping [DatabaseB] DB...';
        ALTER DATABASE [DatabaseB] SET OFFLINE WITH ROLLBACK IMMEDIATE;
        ALTER DATABASE [DatabaseB] SET ONLINE;
        DROP DATABASE [DatabaseB];
    END;
    
    IF (SUSER_ID(N'JohnnyLunchbucket') IS NOT NULL)
    BEGIN
      PRINT 'Dropping [JohnnyLunchbucket] Login...';
      DROP LOGIN [JohnnyLunchbucket];
    END;
    
    IF (OBJECT_ID(N'tempdb..#CertInfo') IS NOT NULL)
    BEGIN
      PRINT 'Dropping [#CertInfo] Temp Table...';
      DROP TABLE #CertInfo;
    END;
    

    设置

    USE [master];
    
    EXECUTE AS LOGIN = N'sa';
    PRINT 'Creating databases...';
    CREATE DATABASE [DatabaseA] COLLATE Latin1_General_100_CI_AS_SC;
    CREATE DATABASE [DatabaseB] COLLATE Latin1_General_100_CI_AS_SC;
    REVERT;
    GO
    
    ALTER DATABASE [DatabaseA] SET DB_CHAINING OFF;
    ALTER DATABASE [DatabaseA] SET TRUSTWORTHY OFF;
    
    ALTER DATABASE [DatabaseB] SET DB_CHAINING OFF;
    ALTER DATABASE [DatabaseB] SET TRUSTWORTHY OFF;
    GO
    
    CREATE LOGIN [JohnnyLunchbucket] WITH PASSWORD = 'OhSoSecure;)';
    
    
    USE [DatabaseA];
    
    CREATE USER [JohnnyLunchbucket] FOR LOGIN [JohnnyLunchbucket];
    GO
    
    CREATE PROCEDURE dbo.RunReport
    AS
    SET NOCOUNT ON;
    
    SELECT * FROM [DatabaseB].[dbo].[RestrictedTable];
    GO
    
    GRANT EXECUTE ON dbo.RunReport TO [JohnnyLunchbucket];
    
    CREATE CERTIFICATE [PermissionsCert]
      AUTHORIZATION [dbo]
      ENCRYPTION BY PASSWORD = 'WeakPassword'
      WITH SUBJECT = 'Used to test granting permissions to code',
      EXPIRY_DATE = '2099-12-31';
    
    ADD SIGNATURE TO [dbo].[RunReport]
        BY CERTIFICATE [PermissionsCert]
        WITH PASSWORD = 'WeakPassword';
    
    SELECT CERTENCODED(CERT_ID(N'PermissionsCert')) AS [PublicKey],
           CERTPRIVATEKEY(CERT_ID(N'PermissionsCert'), 'OtherPassword', 'WeakPassword')
                     AS [PrivateKey]
    INTO   #CertInfo;
    GO
    
    USE [DatabaseB];
    
    DECLARE @SQL NVARCHAR(MAX);
    
    SELECT @SQL = N'CREATE CERTIFICATE [PermissionsCert] AUTHORIZATION [dbo] FROM BINARY = '
                   + CONVERT(NVARCHAR(MAX), [PublicKey], 1)
                   + N' WITH PRIVATE KEY (BINARY = '
                   + CONVERT(NVARCHAR(MAX), [PrivateKey], 1)
                   + N', DECRYPTION BY PASSWORD = N''OtherPassword'''
                   + N', ENCRYPTION BY PASSWORD = ''WeakPassword'');'
    FROM   #CertInfo;
    
    PRINT @SQL;
    EXEC (@SQL);
    
    CREATE USER [PermissionsUser] FROM CERTIFICATE [PermissionsCert];
    
    CREATE TABLE dbo.[RestrictedTable]
    (
      [ID] INT NOT NULL IDENTITY(1, 1)
         CONSTRAINT [PK_RestrictedTable] PRIMARY KEY,
      [Other] VARCHAR(50)
    );
    
    GRANT SELECT ON [dbo].[RestrictedTable] TO [PermissionsUser];
    
    INSERT INTO dbo.[RestrictedTable] ([Other]) VALUES ('Ta da!');
    GO
    

    测试

    -- Quick test to show that [PermissionsUser] cannot be Impersonated:
    USE [DatabaseB];
    EXECUTE AS USER = 'PermissionsUser';
    /*
    Msg 15517, Level 16, State 1, Line 123
    Cannot execute as the database principal because the principal "PermissionsUser" does not
    exist, this type of principal cannot be impersonated, or you do not have permission.
    */
    
    
    -- Main test:
    USE [DatabaseA];
    
    EXECUTE AS LOGIN = 'JohnnyLunchbucket';
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    GO
    
    SELECT * FROM [DatabaseB].[dbo].[RestrictedTable];
    /*
    Msg 916, Level 14, State 1, Line 144
    The server principal "JohnnyLunchbucket" is not able to access the database "DatabaseB"
    under the current security context.
    */
    
    EXEC [dbo].[RunReport]; -- SUCCESS!!!
    -- 1    Ta da!
    
    
    REVERT;
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    GO
    

    有关模拟与模块签名的更多信息,您可以查看我的其他答案(以及其中链接的答案):

    SQL Server 模拟不工作

    • 9
  2. Shaulinator
    2016-12-20T11:35:54+08:002016-12-20T11:35:54+08:00

    在服务器上创建一个用户帐户。在您希望他们具有有限访问权限的数据库中创建没有权限的用户。他们目前无权访问该数据库中的任何内容。

    使用所需的有限列和权限创建所需表的视图。然后配对该用户以访问视图。

    现在在您希望他们使用的数据库中,您可以在那里创建一个过程,该过程引用您想要的视图,同时限制他们的权限并且不允许他们访问基础表,以便他们现在可以进行更高级别的数据聚合。

    这确实违反了无法添加他们对您的问题的请求,但这是一个很好的解决方法,同时让他们除了那个视图之外没有对该数据库中任何内容的实际访问权限。正如您的问题所述,他们不需要访问表,而是访问数据库。您将看到的错误实际上是:

    消息 916,级别 14,状态 1,过程名称,第 11 行服务器主体“USER”无法在当前安全上下文中访问数据库“名称”

    这个想法能解决问题吗?下面的例子。

    CREATE DATABASE TestA; 
    GO
    
    CREATE DATABASE TestB;
    GO
    
    USE [master];
    GO
    
    CREATE LOGIN TestUser WITH PASSWORD = 'Password', CHECK_POLICY = OFF;
    GO
    
    CREATE TABLE TestA.dbo.t1(id INT);
    GO
    
    USE TestA; 
    go 
    
    CREATE VIEW dbo.ViewA
    AS
      SELECT id FROM dbo.t1;
    GO
    
    CREATE USER TestUser FROM LOGIN TestUser;
    GO
    
    GRANT SELECT ON TestA.dbo.ViewA TO TestUser;
    GO
    
    USE TestB;
    GO
    
    CREATE USER TestUser FROM LOGIN TestUser;
    GO
    
    CREATE PROCEDURE dbo.TestProcedure 
    AS
      SELECT id FROM TestA.dbo.ViewA;
    GO
    
    GRANT EXECUTE ON TestB.dbo.TestProcedure TO TestUser;
    GO
    
    • 2
  3. Laughing Vergil
    2016-12-20T12:37:17+08:002016-12-20T12:37:17+08:00

    基本上,您需要在安全数据库之外创建一个进程,以允许非授权用户以非常有限的方式查看数据。执行此操作的最简单方法是创建一个带有 EXECUTE AS 子句的存储过程,为过程中的代码提供公开所选数据所需的权限,但除此之外保持权限锁定。这看起来像:

    Use AccessableDB
    GO
    CREATE PROCEDURE GetTheStuff (Param1 int, Param2 bit = 1)
    WITH EXECUTE AS 'HighPermissionsUserInOtherDB'
    AS
    BEGIN 
        -- Code referencing InaccessableDB
    END
    
    • 2

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve