Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

Calculating a Security Principal’s Effective Rights

$
0
0

Security. Oh that most painful of topics. I discussed it a few months earlier when I discussed the need to give rights only through roles to users, so everything is the same in dev and prod except the users who are placed in each role ( SQL Server Database Security And Source Control ). As I was updating some of our security to use this method, the problem arose that it is hard to know if we got it right. How to make sure that userX who had access to a certain set of objects, still does, even though we have given them access via a different method. This is something that we often wish to know. “Can user X access resource Y?”

So, I went about to build a small utility, most of which is part of this blog. SQL Server gives up tools to determine if a principal has access to an object, so I will introduce them, and then use them to check the “normal” security case, which is trying to determine a user’s rights to access to objects in the database. In a later blog, I will attempt to expand the security beyond object access to all of the various types of security a user may have that we need to track.

SQL Server provides us with two functions that can be used effectively to discover the rights that a user has to an object. It doesn’t tell us HOW the achieved this right, but it tells us if they do have it (how is a bit more complex, and something I plan to tackle some other day!) For example, say a user has SELECT access to TableY. This user could have it directly granted, inherited from a grant at the schema level, inherited through a user-defined role’s access, or even from a built-in role (database or server!)

This is fairly complex, but the general need I am aiming to solve today is to determine what a user has access to. The functions (available in the on-premises and Azure versions) allow you to determine what the current security principal has access to. They are:

HAS_PERMS_BY_NAME This is a scalar function that you can pass in various things like tables and columns, database and server rights. fn_my_permissions This is a table valued function that you can use to return the rights you have for a certain object

The parameters for both include the securable you are checking, and securable class (and subclass for certain things like column level security. The securable class I will be focusing on in this blog is simply ‘OBJECT’, for objects in the database such as tables, procedures, etc. There are quite a few other ones, if you were interested in a complete view of all of the rights a user may have: APPLICATION ROLE, ASSEMBLY, ASYMMETRIC KEY, CERTIFICATE, CONTRACT, DATABASE, ENDPOINT, FULLTEXT CATALOG, LOGIN, MESSAGE TYPE, REMOTE SERVICE BINDING, ROLE, ROUTE, SCHEMA, SERVER, SERVICE, SYMMETRIC KEY, TYPE, USER, XML SCHEMA COLLECTION. For more details, check: HAS_PERMS_BY_NAME and fn_my_permissions .

To get started, I will build a small scenario that will allow me to grant rights, and then change rights around and verify that things match as desired.

CREATE DATABASE PermissionsTest; GO USE PermissionsTest; GO CREATE SCHEMA Demo; GO CREATE TABLE Demo.Table1 (Table1Id int); CREATE TABLE Demo.Table2 (Table2Id int); GO CREATE PROCEDURE Demo.Procedure1 AS SELECT Table1Id FROM Demo.Table1; GO --To this database, we will add a few logins users, and --give them direct access to several of the objects. CREATE LOGIN Login1 WITH PASSWORD = '12345'; CREATE USER User1 FROM LOGIN Login1; CREATE LOGIN Login2 WITH PASSWORD = '12345'; CREATE USER User2 FROM LOGIN Login2; CREATE LOGIN DboLogin WITH PASSWORD = '12345'; CREATE USER DboUser FROM LOGIN DboLogin; --Give User1 access to Table1 and procedure, User2 to Table2 GRANT SELECT ON Demo.Table1 TO User1; GRANT EXECUTE ON Demo.Procedure1 TO User1; GRANT SELECT ON Demo.Table2 TO User2; --put DboUser in the dbo role ALTER ROLE db_owner ADD MEMBER DboUser;

If you want to check if a different user other than the one logged in has access to an object, you will either need to:

Login as that user Impersonate that user

As we typically will be working as a database owner/system administrator when configuring security, we will usually use impersonation to check the user’s rights. For example, if you want to ask SQL Server about a particular object, you might use HAS_PERMS_BY_NAME, in the following manner:

EXECUTE AS USER = 'User1'; --verify the user that you are effectively executing as, --when testing to avoid mistakes SELECT SUSER_NAME() AS server_principal, USER_NAME() AS database_principal; --There are additional parameters to check column level --permissions if you need them SELECT HAS_PERMS_BY_NAME('Demo.Table1','OBJECT','SELECT');

This returns:

server_principal database_principal
-------------------- ------------------------
Login1 User1 -----------
1

Now, checking to see if User1 can access Table2:

SELECT HAS_PERMS_BY_NAME('dbo.Table2','OBJECT','SELECT');

This returns:

―――

0

This function works great if you are checking one item, like from an application before trying to execute it. But if you want to see all of a user’s effective rights on an object, use fn_my_permissions.

For example, if we need to see User1 rights to Table1, we can execute (still in the security context of User1 from the previous code):

SELECT * FROM fn_my_permissions('Demo.Table1', 'OBJECT') AS permissions;

This returns the following, with the row with subentity_name as ” being table permissions, and Table1Id being the column permission:

entity_name subentity_name permission_name
---------------- ----------------- ------------------------
dbo.Table1 SELECT
dbo.Table1 Table1Id SELECT

Now, let’s change back to the security context of the user that is a member of the db_owner role:

REVERT; EXECUTE AS USER = 'DboUser'; SELECT permission_name FROM fn_my_permissions('Demo.Table1', 'OBJECT') AS permissions WHEREpermissions.subentity_name = ''; --ignore column rights

This will show that the dbo user has every possible, logical, right to the table:

permission_name
--------------------------------
SELECT
UPDATE
REFERENCES
INSERT
DELETE
VIEW CHANGE TRACKING
VIEW DEFINITION
ALTER
TAKE OWNERSHIP
CONTROL

Finally, taking this to the final step for this blog, let’s get all of the object level rights for a user in the entire database:

REVERT;

To get all of the user’s rights, take all of the objects in the database, ignoring any objects that have a parent_object_id such as triggers or constraints, and use CROSS APPLY to execute the function for every object.

To make this easier to user, I am going to compile this into a view, called Utility.EffectiveSecurity (and give rig

Viewing all articles
Browse latest Browse all 12749

Trending Articles