授予 ALTER TABLE 权限有多危险?

Mar*_*ith 12 sql-server permissions

想象以下场景

CREATE DATABASE test

GO

USE test;    

CREATE TABLE dbo.Customer
  (
     CustomerId   INT,
     Email        VARCHAR(100),
     SensitiveData VARCHAR(20)
  );

INSERT INTO dbo.Customer
VALUES     (1,'abc@foo.com','12346789');
Run Code Online (Sandbox Code Playgroud)

在某些时候,编写了一个 ETL 过程,在test数据库中执行一些活动。

CREATE USER etlUser WITHOUT LOGIN; /*For demo purposes*/

CREATE TABLE dbo.StagingTable
  (
     StagingTableId INT,
     SomeData       VARCHAR(100),
  )

GRANT UPDATE,INSERT,DELETE,SELECT,ALTER ON dbo.StagingTable TO etlUser;

DENY SELECT ON dbo.Customer TO etlUser;
DENY SELECT ON dbo.Customer (SensitiveData) TO etlUser; /*For good measure*/
Run Code Online (Sandbox Code Playgroud)

etlUser 不应该对Customer表(当然也不是对SensitiveData列)具有权限,因此上面明确拒绝了这些权限。

ETL 过程会截断,dbo.StagingTable因此被授予ALTER表权限。

这在安全审计期间被标记。这个场景有多危险?

Mar*_*ith 17

相当危险...

除了更改StagingTable自身结构的明显权限之外,该ALTER TABLE权限还允许他们在表上创建触发器。因此,在这种情况下,通过所有权链接,他们能够看到敏感的客户数据(尽管有明确的DENY权限)并在第二个表上进行破坏。

EXECUTE AS user='etlUser'

GO

CREATE OR ALTER TRIGGER TR ON dbo.StagingTable AFTER UPDATE AS 
/*Exposure of sensitive data*/
SELECT * FROM dbo.Customer;

/*Vandalism*/
DELETE FROM dbo.Customer;

go

--Fire the trigger
UPDATE dbo.StagingTable SET SomeData = SomeData WHERE 1=0;

REVERT
Run Code Online (Sandbox Code Playgroud)


Sol*_*zky 9

除了能够添加触发器之外,ALTER TABLE权限还允许:

  1. 禁用触发器(避免审计跟踪)
  2. 禁用约束(允许错误数据)
  3. 改变约束(允许坏数据)
  4. 更改列定义(更改数据类型、最大大小、可空性)
  5. 添加一个调用 T-SQL UDF 的计算列(使得获得并行计划非常困难,这很容易损害性能)

它还允许删除列,但这不太可能被忽视(因为我们似乎在这里寻找更具欺骗性而非恶意的潜在操作)。

幸运的是,从来没有必要将此权限授予任何人,也没有必要将其包装在使用该EXECUTE AS子句的存储过程中(通常后跟'dbo'OWNER)。模块签名允许轻松抽象签名代码(存储过程、触发器、标量 UDF 和多语句 TVF)背后的特权操作。我在 DBA.SE 上的以下答案中提供了示例代码,显示了如何完成此操作:

这两个答案之间的区别在于授予基于签名的用户的权限。要授予的权限(或要添加的 DB 角色)取决于所需的范围。如果您只需要对单个表的权限,则只授予ALTER该表的权限。如果特定 Schema 中的所有表都需要权限,则不要向单个表授予权限,而是将权限授予 Schema 本身。等等。

与专门为 ETL 用户创建模式或使用EXECUTE AS子句相比,模块签名是一些额外的步骤,但是:

  1. 鉴于代码在上面链接的两个答案中都可用,它实际上只是一个简单的复制和粘贴,并且
  2. 这当然是最安全的选择。它只允许通过那段代码进行操作,并且只EXECUTE允许那些获得该代码权限的人。作为架构所有者允许某些不必要的隐式权限。而且,使用EXECUTE AS 'dbo'EXECUTE AS OWNER(假设所有者dbo)会给整个过程,从这一点向前,dbo权限,而不仅仅是存储过程/触发器/函数,您使用EXECUTE AS与。模块签名将权限仅限于您签名的代码,而不是签名代码调用的任何代码。

  • 对于某些系统(至少是某些 MySQL 版本),有一种非常卑鄙的方法可以有效地清除 VARCHAR 列,而不会立即被程序错误注意到:将其大小减少到 0。这将清除它,并默默地丢弃任何写入的内容它... (2认同)