【问题标题】:checking permissions inside stored procedure检查存储过程中的权限
【发布时间】:2021-10-26 10:46:54
【问题描述】:

我有一个存储过程 z 读取表 A 并写入表 B + C 必须在 B 和 C 之间过程不停止(金融交易,比如你不能在不从 C 中获取的情况下添加到 B)

为了避免这种情况,并且因为运行该过程的用户不应该对 A、B 或 C 有任何权限,并且有时服务器连接可能会断开,我构建了以下内容:

ALTER PROCEDURE [INV].[Z]
    AS
    BEGIN
    DECLARE @CanAcessAllTables int = 
        (SELECT IIF( (SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME in (A, B, C) ) = 3, 1, 0))
    IF      @CanAcessAllTables <> 1
        RAISERROR('Looks like we either can not connect to the server or you lack some aditional permissions', 16, 16)
    ELSE
        BEGIN TRY
            BEGIN TRANSACTION
                INSERT INTO [INV].[B] ( col1,  col2) VALUES (1, 2)
                INSERT INTO [INV].[C] ( col3,  col4) VALUES (1, 2)

            COMMIT TRANSACTION
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION
            SELECT 'Please report the following table for support:'
            SELECT
                ERROR_MESSAGE()   as ErrorMessage,
                ERROR_PROCEDURE() as ErrorProcedure,
                ERROR_LINE()      as ErrorLine,
                ERROR_STATE()     as ErrorState,
                ERROR_SEVERITY()  as ErrorSeverity,
                ERROR_NUMBER()    as ErrorNumber
        END CATCH
END
GO

我的想法是 sp 会检查他(sp)是否可以访问所有 3 个表,而不是检查运行 Z 的用户是否可以访问所有 3 个表,自然用户没有对所有 3 个和结果的权限在“看起来我们要么无法连接到服务器,要么您缺少一些额外的权限”错误 这有点讽刺,因为通过消除该引发错误,sp 将运行。

那么我的问题是,我应该用什么来确保在任何情况下 B 和 C 一起运行或根本不运行(即使有人将表 B 重命名为 B_1 或撤销 sp 对 C 的写权限)

【问题讨论】:

  • 您的顾虑纵横交错。如果您使用 RBAC 并且需要与表相同的角色来访问存储过程,则 AuthX 可以由 SQL Server 直接处理。
  • " '请报告下表以获得支持:'" INSERT INTO 是自找麻烦。 INSERT 语句中始终使用明确的列名
  • 如果所有权链未中断,则不会检查 proc 使用的表的权限(如这里所示)。
  • 另外,您的 human 用户真的都有不同的 SQL LOGINUSER 对象吗?这些天很少发生这种事情......
  • 只需重新抛出错误,或者,抛出一个通用但用户友好的错误并在某处记录实际错误。并且不要使用 SELECT 生成包含“友好”消息供应用程序处理的结果集。您的应用程序应该足够智能以直接提供(如果服务或批处理正在执行此操作,则不提供)。您将自己的假设推入您的程序逻辑中。

标签: sql-server tsql security stored-procedures


【解决方案1】:

在 T-SQL 中使用 TRY\CATCH 处理错误通常是浪费时间,除非您有处理某个错误的特定方法。

使用SELECT ERROR_MESSAGE() 只会破坏完整的异常跟踪,因为可能存在多个异常。

如果您要提出特定的业务错误(不仅仅是无论如何都会抛出的权限错误),请使用THROW

最好的方法是使用SET XACT_ABORT ON;,这将保证任何异常都会导致立即回滚,无论连接是否中断是权限问题。

为确保事务的隔离性和原子性,您可以使用隔离级别SERIALIZABLE,但代价是锁越来越多,因此锁和阻塞的风险更高。 p>

ALTER PROCEDURE [INV].[Z]
AS

SET XACT_ABORT, NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;
    IF(NOT EXISTS (SELECT 1 FROM SomeTableToCheck WHERE Something = 1))
        THROW 50000, 'Some business error', 0;

    INSERT INTO [INV].[B] ( col1,  col2) VALUES (1, 2);
    INSERT INTO [INV].[C] ( col3,  col4) VALUES (1, 2);
COMMIT TRANSACTION

GO

【讨论】:

  • 谢谢!我想我需要对这些功能进行一些研究
猜你喜欢
  • 2017-09-17
  • 2012-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 2011-09-22
  • 2011-04-02
相关资源
最近更新 更多