如何拒绝所有用户 SQL 服务器的 INSERT 权限

How to deny INSERT permission to all users SQL Server

我们目前正在从在我们的应用程序中使用 sa 凭据(这是愚蠢的)过渡。

但我对 SQL 服务器中的权限系统感到头疼,我不知道哪里出了问题,而且它根本不起作用。

这是我使用的 SQL 语句:

CREATE SCHEMA [audit]
GO

BEGIN TRAN T1
USE [master]

CREATE LOGIN [pcm-api_access_logs]
  WITH PASSWORD = 'verysecretpassword',
  DEFAULT_DATABASE = PCM;

USE [PCM]

CREATE USER [access_logs] FOR LOGIN [pcm-api_access_logs] WITH DEFAULT_SCHEMA = [audit]
CREATE USER [audit_agent] WITHOUT LOGIN WITH DEFAULT_SCHEMA = [audit]
CREATE USER [audit] WITHOUT LOGIN WITH DEFAULT_SCHEMA = [audit]

ALTER AUTHORIZATION ON SCHEMA :: [audit] TO [audit];

DENY ALTER,CONTROL ON SCHEMA :: [audit] TO public;
-- REVOKE ALTER,CONTROL ON SCHEMA :: [audit] FROM audit_agent;
-- REVOKE ALTER,CONTROL ON SCHEMA :: [audit] FROM access_logs;

GRANT SELECT ON SCHEMA :: [audit] TO [access_logs] WITH GRANT OPTION;
-- GRANT INSERT ON SCHEMA :: [audit] TO [audit_agent] WITH GRANT OPTION;

CREATE TABLE [audit].[accessLogs] 
(
    [id] INT PRIMARY KEY IDENTITY(1, 1),
    [action] VARCHAR(32) NOT NULL,
    [date] DATETIME DEFAULT GETUTCDATE(),

    [userId] INT NULL,
    [documentId] INT NULL,
    [directoryId] INT NULL,
    [supplierId] INT NULL,

    [message] VARCHAR(200) NOT NULL
)

ALTER AUTHORIZATION ON OBJECT::[audit].[accessLogs] TO [audit];
GO

CREATE PROCEDURE [audit].[uspGetAccessLogEntries]
    (@user_id INT = null)
AS 
BEGIN
    DECLARE @isValid BIT = 0

    IF @user_id IS NOT NULL 
    BEGIN
        SET @isValid = 1
    END

    SELECT 
        [error] = NULL,
        [verified] = @isValid

    SELECT *
    FROM [audit].[accessLogs]
END
GO

CREATE PROCEDURE [audit].[uspAddAccessLogEntry]
    (@action VARCHAR(32),
     @message VARCHAR(200),
     @user_id INT = NULL,
     @document_id INT = NULL,
     @directory_id INT = NULL,
     @supplier_id INT = NULL)
WITH EXECUTE AS 'audit_agent'
AS 
BEGIN
    SELECT [current-user] = CURRENT_USER;

    INSERT INTO [audit].[accessLogs] ([action], [message], [userId], [documentId], [directoryId], [supplierId])
    VALUES (@action, @message, @user_id, @document_id, @directory_id, @supplier_id)
END
GO

TRUNCATE TABLE audit.accessLogs
EXEC [audit].[uspAddAccessLogEntry] 'login', 'user ''vangeyja'' has logged in at {{date}}.', 1

EXEC [audit].[uspGetAccessLogEntries] 1

ROLLBACK TRAN T1

DROP SCHEMA [audit]
GO

回滚事务并删除架构,因此您可以 运行 自己轻松完成。

当我 运行 在 sp [uspAddAccessLogEntry] 中插入时 运行 没有问题。由于我没有授予 audit_agent 权限,我希望这会失败 运行ning。如果 public 级联权限存在任何问题,我已经尝试对 public 角色的整个架构设置拒绝。

我想要的;创建一个只能由审计或 sa 用户(系统管理员角色)访问的模式审计用户 audit_agent 应该只在 accessLogs 上插入,用户 access_logs 应该只在 accessLogs 上有 SELECT .

所有其他数据库用户不应该能够读写或对审计架构及其对象执行任何操作。

对存储过程、视图或函数具有直接权限的用户不需要对间接引用的对象具有权限,只要对象所有者相同即可。这种行为称为所有权链接。

您可以利用所有权链来严格限制通过存储过程对数据的访问,而不能直接访问表。仅具有执行权限的用户仅限于 proc 封装的功能。

请注意,普通用户最初没有权限。没有必要引入 DENY 除非在特殊情况下 GRANT 是通过角色的成员资格继承的,这里不是这种情况。

特权用户是一个需要考虑的例外:

  • sysadmin 服务器角色角色成员
  • db_owner 角色成员
  • 对象所有者(默认继承自架构所有者)

create a schema audit which can only be accessed by the audit or sa user

我从过程中删除了 EXECUTE AS,因为它不需要。

CREATE SCHEMA audit;
GO
ALTER AUTHORIZATION ON SCHEMA::audit TO audit;
GO

CREATE TABLE [audit].[accessLogs] 
(
    [id] INT PRIMARY KEY IDENTITY(1, 1),
    [action] VARCHAR(32) NOT NULL,
    [date] DATETIME DEFAULT GETUTCDATE(),

    [userId] INT NULL,
    [documentId] INT NULL,
    [directoryId] INT NULL,
    [supplierId] INT NULL,

    [message] VARCHAR(200) NOT NULL
)

ALTER AUTHORIZATION ON OBJECT::[audit].[accessLogs] TO [audit];
GO

CREATE PROCEDURE [audit].[uspGetAccessLogEntries]
    (@user_id INT = null)
AS 
BEGIN
    DECLARE @isValid BIT = 0

    IF @user_id IS NOT NULL 
    BEGIN
        SET @isValid = 1
    END

    SELECT 
        [error] = NULL,
        [verified] = @isValid

    SELECT *
    FROM [audit].[accessLogs]
END
GO

CREATE PROCEDURE [audit].[uspAddAccessLogEntry]
    (@action VARCHAR(32),
     @message VARCHAR(200),
     @user_id INT = NULL,
     @document_id INT = NULL,
     @directory_id INT = NULL,
     @supplier_id INT = NULL)
AS 
BEGIN
    SELECT [current-user] = CURRENT_USER;

    INSERT INTO [audit].[accessLogs] ([action], [message], [userId], [documentId], [directoryId], [supplierId])
    VALUES (@action, @message, @user_id, @document_id, @directory_id, @supplier_id)
END
GO

the user audit_agent should only have INSERT on accessLogs

GRANT EXECUTE ON [audit].[uspAddAccessLogEntry] TO audit_agent;

the user access_logs should only have SELECT on accessLogs.

GRANT EXECUTE ON [audit].[uspGetAccessLogEntries] TO access_logs;

测试权限:

EXECUTE AS USER = 'audit_agent';
GO
SELECT * FROM audit.accessLogs --select permission denied
EXEC [audit].[uspGetAccessLogEntries] --execute permission denied
EXEC [audit].[uspAddAccessLogEntry] ... --success
GO
REVERT
GO


EXECUTE AS USER = 'access_logs';
GO
SELECT * FROM audit.accessLogs --select permission denied
EXEC [audit].[uspAddAccessLogEntry] ... --execute permission denied
EXEC [audit].[uspGetAccessLogEntries] --success
GO
REVERT
GO