Sql-server – Does this mean the ‘public’ has full select, insert, update, and delete access

permissionsSecuritysql serversql-server-2008sql-server-2008-r2

I'm trying to create a new DB user in SQL Server 2008 R2 that can only select from one SQL View. But no matter what I try when I login as this new user I can select from any table. I ran this query:

select  princ.name
,       princ.type_desc
,       perm.permission_name
,       perm.state_desc
,       perm.class_desc
,       object_name(perm.major_id)
from    sys.database_principals princ
left join
        sys.database_permissions perm
on      perm.grantee_principal_id = princ.principal_id
WHERE princ.name = 'public'
AND object_name(perm.major_id) = 'User_Table'

And get these results:

name    type_desc       permission_name     state_desc  class_desc          (No column name)
public  DATABASE_ROLE   DELETE              GRANT       OBJECT_OR_COLUMN    User_Table
public  DATABASE_ROLE   INSERT              GRANT       OBJECT_OR_COLUMN    User_Table
public  DATABASE_ROLE   REFERENCES          GRANT       OBJECT_OR_COLUMN    User_Table
public  DATABASE_ROLE   SELECT              GRANT       OBJECT_OR_COLUMN    User_Table
public  DATABASE_ROLE   UPDATE              GRANT       OBJECT_OR_COLUMN    User_Table

Does this mean no matter what anyone that logs in into the database will have full access based on the 'public' permissions?

Best Answer

This means that if the user has not had permissions explicitly set for the securable (or inherited from permissions explicitly set) that public has permissions for, then those will be applied. In other words, if you have User1 with DELETE permissions denied on User_Table, then User1 will not be able to delete data from that table.

Please see BOL's reference on Database-Level Roles:

public Database Role
Every database user belongs to the public database role. When a user has not been granted or denied specific permissions on a securable object, the user inherits the permissions granted to public on that object.

Example

use TestDB;
go

create login Login1
with
    password = 'password',
    check_policy = off;
go

create user User1
for login Login1;
go

-- this will return 1 (meaning, yes it is a role member)
select is_rolemember('public', 'User1');


-- let's do a test to show the above theory
create table SomeTable
(
    id int identity(1, 1) not null,
    SomeText varchar(30) not null
        default replicate('a', 30)
);
go

insert into SomeTable
values(default);
go 10

-- give the public role permissions to SELECT on SomeTable
grant select
on SomeTable
to public;
go

-- this will be successful, because User1 is part of public
execute as user = 'User1';
go

select *
from SomeTable;

revert;
go


-- create a new role to deny SELECT on SomeTable
exec sp_addrole 'Role1';
go

deny select
on SomeTable
to Role1;
go

-- add User1 to this new role
exec sp_addrolemember 'Role1', 'User1';
go


-- this will not be successful because User1 now has been denied SELECT on SomeTable
execute as user = 'User1';
go

select *
from SomeTable;

revert;
go