Home > Software design >  How to deny INSERT permission to all users SQL Server
How to deny INSERT permission to all users SQL Server

Time:04-22

We are currently transitioning from using sa credentials in our applications (which is stupid).

But I'm breaking my head over the permission system in SQL Server, I have no clue what could be going wrong and no way it just doesn't work.

This is the SQL statement I used:

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

The transaction is rolled back and the schema is dropped so you can run it yourself with ease.

When I run this The Insert within the sp [uspAddAccessLogEntry] just runs without problems. Since I have not given the permissions to audit_agent, I expect this to fail running. I already tried putting a DENY on the whole schema for the public role if there was any issue with public cascading permissions.

What I want; create a schema audit which can only be accessed by the audit or sa user (sysadmin role) the user audit_agent should only have INSERT on accessLogs, the user access_logs should only have SELECT on accessLogs.

all other db users should not be able to read write or do anything on the audit schema and its objects.

CodePudding user response:

Users with direct permissions on a stored procedure, view, or function do not need permissions on indirectly referenced objects as long as the object owners are the same. This behavior is called ownership chaining.

You can leverage ownership chaining to limit access to data strictly via stored procedures with no direct access to tables. Users with only execute permissions are limited to the functionality encapsulated by the proc.

Note that normal users have no permissions initially. There is no need to introduce DENY except in special cases where a GRANT was inherited via membership of a role, which is not the case here.

Privileged users are an exception to consider:

  • sysadmin server role role members
  • db_owner role members
  • object owner (inherited from the schema owner by default)

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

I removed EXECUTE AS from the proc as it is not needed.

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;

Test permissions:

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
  • Related