Security with Ownership Chains
Security with Ownership Chains
Ownership chaining is one of my favorite SQL Server security features. I like ownership chaining because it allows me to confine data access to specific stored procedures, views and functions while preventing direct access to the underlying tables. This approach provides a well-defined application interface that insulates applications from the physical implementation and allows me to change things on the back-end as long as I don’t change the interface. Also, thanks to ownership chaining, I have many options to vertically and horizontally partition data to meet security objectives while ensuring tables are not accessed directly.
Ignorance is not bliss when it comes to ownership chaining security, though. I’ve seen cases where data access was inadvertently allowed because ownership chaining wasn’t considered. It is imperative that SQL Server DBAs understand ownership chaining in the SQL Server security model so that data is properly secured. I want to point out a couple of important security concepts as it relates to ownership chaining with the hope that it will help SQL Server DBAs implement a security scheme that is appropriate for their environment and also easy to manage.
Ownership Chain Behavior
SQL Server always checks permissions on directly referenced objects using the current connection security context. However, permissions are evaluated differently when objects are accessed indirectly, such as those used in a trigger, view or stored procedure. The behavior of ownership chaining is that object permissions are not evaluated when the calling and referenced object owners are the same. Also, because object permission checking is short-circuited in an unbroken chain, ownership chaining takes precedence over an impersonated security context (EXECUTE AS clause) as well as denied object permissions. Consequently, permissions on indirectly referenced objects are irrelevant in an unbroken ownership chain. This ownership chaining behavior gives a DBA control over exactly who can use which objects while preventing ad-hoc access to other objects.
Ownership chaining behavior might not be intuitive at first. I like to think of it from the perspective that the purpose of granting object permissions is so the object can actually be used. For example, it is of no use to grant a user SELECT permissions on a view unless data can be retrieved from the view. The same applies even when a stored procedure or function impersonates with EXECUTE AS; the impersonated principal must be able to use objects referenced by the proc in order for the procedure to be useful. I keep in mind that with ownership chaining, I effectively grant permissions on exposed object functionality regardless of how the functionality is implemented.
Ownership chaining is limited to a single owner in order to prevent escalation of privileges in environments where non-privileged users can create objects. Ownership chaining also does not apply to dynamic SQL executed from a stored procedure; the invoking (or impersonated) user needs permissions on objects referenced by dynamic SQL statements. I should add that a one of the useful purposes of EXECUTE AS and signing modules with certificates is to provide needed permissions in a broken ownership chain or granting statement permissions without granting user permissions directly. See SQL Server MVP Erland Sommarskog’s article Giving Permissions through Stored Procedures for a discussion of these techniques.
Ownership Best Practices
Ownership is obviously central to ownership chaining. In the vast majority of environments, it’s probably best to simply inherit the owner (a.k.a. AUTHORIZATION) from the object’s schema instead of overriding on individual objects. It is possible to assign ownership to individual objects (using ALTER AUTHORIZATION) in order to implement chaining that is independent of schema but I think this is overly complex for most environments. One reason I can think of why one might specify a different owner at the object level is in the case where a table contains particularly sensitive data and one wants to deliberately prevent inadvertent access via ownership chaining. I think such cases are rare, though.
I described some of the practices I follow for schema and object ownership in Keep Schema and Ownership Simple. In summary, I specify dbo as the schema authorization (owner) unless I want to break the ownership chain between schemas to create a security boundary. When a security boundary is desired, I create a role (or user without login) with the same name as the schema for the schema authorization.