【问题标题】:Sql Server: how to write trigger on a table with denied SELECTSql Server:如何在拒绝 SELECT 的表上编写触发器
【发布时间】:2023-03-23 22:11:02
【问题描述】:

您好,我有一张表拒绝向用户提供 SELECT privs。
该表有一个引用 INSERTED 表的触发器,基本上是在做一个

AFTER UPDATE SET <table>.[UPDATED] = getdate() 
  WHERE ROWID IN SELECT ROWID FROM INSERTED

它给了我一个错误,说“SELECT PERMISSIONS DENIED”,我猜是因为 SELECT FROM INSERTED。

如何保持 SELECT 拒绝,但允许触发器从 INSERTED 伪表中进行 SELECT?

提前致谢!

【问题讨论】:

    标签: sql-server permissions triggers access-denied


    【解决方案1】:

    加入插入的表,而不是像:

    update t1
    set updated = getdate()
    from table1 t1
    join inserted i
    on i.rowid = t1.rowid
    

    无论如何,这也可能比子选择更好。

    【讨论】:

    • 嗯...不行。只是为了好玩,我尝试注释掉触发器主体,所以它不应该选择任何东西,但我仍然得到错误。我真的不知道为什么,因为我所做的只是更新站点。CONTENT SET NAME = '联系我们', CONTENT = '你好!您可以拨打 212.555.1212 联系我们。

      Wicked Cheers!
      ' WHERE ROWID = 2 并且桌面上只有一个触发器。所以我看不到它在哪里做 SELECT。甚至 SQL Profiler 也不会显示事务中发生的任何 SELECT 语句。 GRRR ...好吧,无论如何,谢谢,我想我得回去看看这个。
    • (哎呀,发cmets时没有意识到它没有使用格式规则)
    【解决方案2】:

    你为什么拒绝选择?只是不授予他们选择权怎么办?拒绝选择和不授予选择之间存在细微差别。此外,如果您拒绝选择任何系统级角色,那么这也可能是问题的一部分。

    --编辑--

    在 cmets 中,您询问 SQL Server 是否有上下文信息。 2005 有,你可以看看如何使用它here

    会话变量 – Context_Info:会话是任何编程语言中的强大工具。 SQL-Server 不是一种完整的编程语言,但它确实支持当前会话或连接的会话变量。它将会话的值存储在 128 字节的二进制信息中。

    【讨论】:

    • 嗯,我们有一个数据库,它在几个表上都有一个 SITEID,并且正在使用它来重新创建 ORACLE 的虚拟数据库功能......所以多个网站运行这个数据库,然后他们按 SITEID 从这些表中过滤结果。我想做的是拒绝表上的 SELECT,并强制网站登录使用一组表值函数来访问这些表,这些表以 SITEID 作为参数。这样,如果 SITEID 取回所有站点的记录,站点就不会无意中执行 SELECT。
    • 也许存储过程才是你真正想要的。或者,也许按站点 ID 过滤的视图最好?但是,拒绝选择不会帮助您解决这个问题。
    • 嗯,拒绝选择实际上只是为了强制确保没有任何网络代码无意中直接调用表。我认为这些功能确实是最好的,因为您不能直接从存储过程的表结果中进行选择。使用表值函数允许在 select 语句中直接使用函数名。但即使使用 sproc 或 TVF,仍有可能意外地从主表中进行选择。 Sql 是否提供了一种执行参数化视图的方法?还是您的意思是每个网站都有一个单独的视图?
    • 每个站点的单独视图。
    • 是的,这真的不理想,因为这样每个站点都会有一个单独的副本,并且它是 5 个表,因此 4 个站点会用 20 个不同的视图使数据库变得混乱。谢谢你的想法。 Sql Server 实际上并没有像 Oracle 的 VDB 那样支持 CONTEXT 变量的想法,是吗?
    【解决方案3】:

    我怀疑您的问题是您的 UPDATE 语句本身需要 SELECT 权限。

    我创建了一个测试数据库如下:

    DROP DATABASE triggerPermissionTest
    CREATE DATABASE triggerPermissionTest
    GO
    USE triggerPermissionTest
    GO
    CREATE USER foo FROM LOGIN tester
    GO
    CREATE TABLE triggerTable (id int)
    GO
    DENY SELECT ON triggerTable to foo
    GRANT UPDATE ON triggerTable to foo
    GO
    CREATE TRIGGER execAsTrigger ON triggerTable
    AFTER UPDATE AS SELECT * FROM triggerTable
    GO
    INSERT INTO triggerTable VALUES (1)
    GO

    并使用“tester”登录尝试了以下更新语句:

    UPDATE triggerTable SET id = 2
    GO
    UPDATE triggerTable SET id = id *2
    GO

    第一个执行良好,触发器执行(将 select * from triggerTable 的结果提供给没有选择权限的用户,证明它设法进行了选择)。

    第二个给我一个错误,指出我没有对 triggerTable 的选择权限(因为它需要从 triggerTable 中选择才能获取 id 的值来进行更新)。

    这使我得出结论,触发器是问题的附带原因,而 UPDATE 语句是权限问题的原因。

    【讨论】:

      【解决方案4】:

      考虑添加一个 EXECUTE AS 子句,以便触发器以架构所有者的权限运行。

      CREATE TRIGGER [dbo].[TR_Product_Update] ON [Product]
         WITH EXECUTE AS OWNER
         AFTER UPDATE
      AS
      SELECT ProductId
      FROM INSERTED
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-13
        • 2022-07-12
        • 2012-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多