AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 161037
Accepted
Dave.Gugg
Dave.Gugg
Asked: 2017-01-14 14:39:03 +0800 CST2017-01-14 14:39:03 +0800 CST 2017-01-14 14:39:03 +0800 CST

Permissões em gatilhos ao usar certificados cruzados de banco de dados

  • 772

Eu uso certificados de bancos de dados cruzados ( conforme explicado por Erland Sommarskog ) para controlar o acesso a um determinado banco de dados em meu ambiente (SQL Server 2008 R2).

Eu armazenei procedimentos no banco de dados A que atualizam tabelas no banco de dados B. Isso sempre funcionou para uma variedade de procedimentos armazenados no banco de dados A e tabelas no banco de dados B até agora. Estou tentando atualizar uma tabela no banco de dados B, mas a tabela possui um gatilho. Este gatilho está inserindo dados adicionais em outra tabela no db B. Estou recebendo o erro:

Msg 916, Nível 14, Estado 1, Procedimento table_trigger, Linha 11 O servidor principal "sql\login" não pode acessar o banco de dados "B" no contexto de segurança atual.

Tentei conceder permissões de inserção para o usuário do banco de dados B que está vinculado ao certificado para inserir nessa outra tabela, mas não resolveu o erro. Tenho outras opções além de alterar o gatilho para que ele use WITH EXECUTE AS OWNER?

Aqui está o DDL para replicar o problema:

CREATE LOGIN [GuggTest] WITH PASSWORD=N'abcd', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

CREATE DATABASE A;
CREATE DATABASE B;

USE A;

CREATE TABLE dbo.SPtoUpdate
    (
      ID INT
    , ILoveFishing VARCHAR(255)
    );
INSERT INTO dbo.SPtoUpdate
        ( ID , ILoveFishing )
VALUES  ( 1,'Musky'),( 2,'Pike'),( 3,'Yellow Perch');
CREATE TABLE dbo.TriggerToInsert
    (
      ID INT
    , ILoveFishing VARCHAR(255)
    , ChangeDate DATETIME2
    );
GO

CREATE TRIGGER dbo.SPtoUpdateTrigger ON dbo.SPtoUpdate
    FOR UPDATE
AS
    DECLARE @datetime DATETIME2;
    SELECT  @datetime = GETDATE()

    INSERT  INTO dbo.TriggerToInsert
            ( ID , ILoveFishing , ChangeDate )
    VALUES  ( 1 , 'Yes' , @datetime );
GO

CREATE CERTIFICATE BExecutor
   ENCRYPTION BY PASSWORD = 'Obfuscated'
   WITH SUBJECT = 'Execute sp from B to A',
   START_DATE = '20140101', EXPIRY_DATE = '20300101'
GO

BACKUP CERTIFICATE BExecutor TO FILE = 'C:\temp\crossdbcert.cer'
WITH PRIVATE KEY (FILE = 'C:\temp\crossdbcert.pvk' ,
                  ENCRYPTION BY PASSWORD = 'Obfuscated',
                  DECRYPTION BY PASSWORD = 'Obfuscated')
GO

CREATE USER BExecutor FROM CERTIFICATE BExecutor

GRANT UPDATE ON dbo.SPtoUpdate TO BExecutor
GRANT SELECT ON dbo.SPtoUpdate TO BExecutor
--Also give insert on dbo.TriggerToInsert
GRANT INSERT ON dbo.TriggerToInsert TO BExecutor

USE B
GO

CREATE USER [GuggTest] FOR LOGIN [GuggTest];
EXEC sp_addrolemember N'db_owner', N'GuggTest'
GO

CREATE PROCEDURE dbo.UpdateTableInA
AS
    BEGIN
        UPDATE  A.dbo.SPtoUpdate
        SET     ILoveFishing = 'Walleye'
        WHERE   ID = 2;
    END

GO


CREATE CERTIFICATE BExecutor FROM FILE = 'C:\temp\crossdbcert.cer'
WITH PRIVATE KEY (FILE = 'C:\temp\crossdbcert.pvk' ,
                  ENCRYPTION BY PASSWORD = 'Obfuscated',
                  DECRYPTION BY PASSWORD = 'Obfuscated')
GO

EXEC master..xp_cmdshell 'DEL C:\temp\crossdbcert.*', 'no_output'
GO

ADD SIGNATURE TO dbo.UpdateTableInA BY CERTIFICATE BExecutor
    WITH PASSWORD = 'Obfuscated'
GO

--Log In or Change execution context to GuggTest, then EXEC dbo.UpdateTableInA
sql-server permissions
  • 1 1 respostas
  • 2468 Views

1 respostas

  • Voted
  1. Best Answer
    Solomon Rutzky
    2017-01-19T09:25:02+08:002017-01-19T09:25:02+08:00

    O problema aqui é que, enquanto o certificado vincula o procedimento armazenado no banco de dados A com o usuário no banco de dados B que possui INSERTpermissões nas duas tabelas, o gatilho na tabela que está sendo inserido diretamente do procedimento armazenado é outro módulo na cadeia e as permissões adquiridas de Certificados não passam para outros módulos em uma cadeia. Ou seja, o Certificado permitia que o Stored Procedure inserisse na tabela através do User, e até mesmo executasse o Trigger. Mas, nenhuma permissão foi dada ao Trigger para fazer qualquer coisa relacionada a objetos (fazer algo como SELECT 1;funcionaria).

    Nesse caso, é necessário dar permissões ao Trigger, por meio desse mesmo Certificado, para que ele possa tomar as providências necessárias. Isso pode ser feito, no mínimo, assinando o Gatilho. E você faz isso executando ADD COUNTER SIGNATURE TO [TriggerSchema].[TriggerName] BY CERTIFICATE ...;. Depois disso, ele deve funcionar, mesmo sem INSERTpermissão direta para o usuário baseado em certificado na tabela que está sendo inserida pelo gatilho.

    O código de exemplo abaixo reproduz o problema, corrige o problema adicionando uma contra-assinatura, mas não concede INSERTpermissões para a tabela preenchida pelo gatilho.

    LIMPAR

    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;
    

    CONFIGURAR

    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
    
    -- Default for both options should be OFF, but just to be sure:
    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
    
    --DROP PROCEDURE dbo.InsertIntoTableWithoutTrigger;
    CREATE PROCEDURE dbo.InsertIntoTableWithoutTrigger
    (
        @SomeValue NVARCHAR(50)
    )
    AS
    SET NOCOUNT ON;
    
    INSERT INTO [DatabaseB].[dbo].[TableWithoutTrigger] (SomeValue)
    VALUES (@SomeValue);
    GO
    
    GRANT EXECUTE ON dbo.InsertIntoTableWithoutTrigger TO [JohnnyLunchbucket];
    GO
    
    CREATE PROCEDURE dbo.InsertIntoTableWithTrigger
    AS
    SET NOCOUNT ON;
    
    INSERT INTO [DatabaseB].[dbo].[TableWithTrigger] (SomeOtherValue)
    VALUES (NEWID());
    GO
    
    GRANT EXECUTE ON dbo.InsertIntoTableWithTrigger 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].[InsertIntoTableWithoutTrigger]
        BY CERTIFICATE [PermissionsCert]
        WITH PASSWORD = 'WeakPassword';
    
    ADD SIGNATURE TO [dbo].[InsertIntoTableWithTrigger]
        BY CERTIFICATE [PermissionsCert]
        WITH PASSWORD = 'WeakPassword';
    
    -- Save Certificate info in temporary table so we can recreate in DatabaseB
    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];
    
    --DROP TABLE dbo.[TableWithoutTrigger];
    CREATE TABLE dbo.[TableWithoutTrigger]
    (
      [TableWithoutTriggerID] INT NOT NULL IDENTITY(1, 1)
         CONSTRAINT [PK_TableWithoutTrigger] PRIMARY KEY,
      [SomeValue] NVARCHAR(50)
    );
    
    GRANT INSERT ON [dbo].[TableWithoutTrigger] TO [PermissionsUser];
    
    
    CREATE TABLE dbo.[TableWithTrigger]
    (
      [TableWithTriggerID] INT NOT NULL IDENTITY(1, 1)
         CONSTRAINT [PK_TableWithTrigger] PRIMARY KEY,
      [SomeOtherValue] NVARCHAR(50)
    );
    
    GRANT INSERT ON [dbo].[TableWithTrigger] TO [PermissionsUser];
    
    
    CREATE TABLE dbo.[TablePopulatedByTrigger]
    (
      [TablePopulatedByTriggerID] INT NOT NULL IDENTITY(1, 1)
         CONSTRAINT [PK_TablePopulatedByTrigger] PRIMARY KEY,
      [DuplicatedValue] NVARCHAR(50)
    );
    GO
    
    CREATE TRIGGER dbo.CopySomeOtherValue
    ON dbo.[TableWithTrigger]
    AFTER INSERT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        INSERT INTO dbo.[TablePopulatedByTrigger] ([DuplicatedValue])
            SELECT ins.[SomeOtherValue]
            FROM   inserted ins;
    END;
    GO
    

    TESTE 1: Gatilho falha

    USE [DatabaseA];
    
    EXECUTE AS LOGIN = 'JohnnyLunchbucket';
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    GO
    
    SELECT * FROM [DatabaseB].[dbo].[TableWithoutTrigger];
    SELECT * FROM [DatabaseB].[dbo].[TableWithTrigger];
    SELECT * FROM [DatabaseB].[dbo].[TablePopulatedByTrigger];
    INSERT INTO [DatabaseB].[dbo].[TableWithoutTrigger] ([SomeValue]) VALUES (N'test 0');
    USE [DatabaseB];
    /* -- All 5 statements above get the following error:
    Msg 916, Level 14, State 1, Line xxxxxx
    The server principal "JohnnyLunchbucket" is not able to access the database
        "DatabaseB" under the current security context.
    */
    
    
    EXEC [dbo].[InsertIntoTableWithoutTrigger] @SomeValue = N'test A'; -- SUCCESS!!!
    
    EXEC [dbo].[InsertIntoTableWithTrigger]; -- ERROR:
    /*
    Msg 916, Level 14, State 1, Procedure CopySomeOtherValue, Line xxxxxx
    The server principal "JohnnyLunchbucket" is not able to access the database
        "DatabaseB" under the current security context.
    */
    
    REVERT;
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    
    -- Check to make sure that dbo.InsertIntoTableWithoutTrigger really did work:
    SELECT * FROM [DatabaseB].[dbo].[TableWithoutTrigger];
    -- 1    test A
    

    TESTE 2: O gatilho é bem-sucedido

    Observe que a única alteração feita é ADD COUNTER SIGNATURE; não há GRANT INSERT ON dbo.TablePopulatedByTrigger TO [PermissionsUser];.

    USE [DatabaseB];
    
    ADD COUNTER SIGNATURE
        TO dbo.[CopySomeOtherValue]
        BY CERTIFICATE [PermissionsCert]
        WITH PASSWORD = 'WeakPassword';
    GO
    
    
    USE [DatabaseA];
    
    EXECUTE AS LOGIN = 'JohnnyLunchbucket';
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    GO
    
    INSERT INTO [DatabaseB].[dbo].[TableWithTrigger] ([SomeOtherValue]) VALUES (N'Test B');
    INSERT INTO [DatabaseB].[dbo].[TablePopulatedByTrigger]([DuplicatedValue]) VALUES ('Test B')
    /*
    Msg 916, Level 14, State 1, Line xxxxxx
    The server principal "JohnnyLunchbucket" is not able to access the database
        "DatabaseB" under the current security context.
    */
    
    
    EXEC [dbo].[InsertIntoTableWithTrigger]; -- SUCCESS!!!
    
    REVERT;
    SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
    
    SELECT * FROM [DatabaseB].[dbo].[TableWithTrigger];
    SELECT * FROM [DatabaseB].[dbo].[TablePopulatedByTrigger];
    -- 2    968DB092-C3DE-4E4B-92B9-E21CA551A5FA
    -- 1    968DB092-C3DE-4E4B-92B9-E21CA551A5FA
    
    • 8

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve