The most common method of securing SQL Server
resources is to deny database users any direct access to SQL Server
resources and provide access only via stored procedures or views. If a
database user has access to execute a stored procedure, and the stored
procedure is owned by the same database user that owns a resource being
referenced within the stored procedure, the user executing the stored
procedure will be given access to the resource, via the stored
procedure. This is called an ownership chain.
To illustrate, start by creating and switching to a test database:
CREATE DATABASE OwnershipChain
GO
USE OwnershipChain
GO
Now, create two database users, Louis and Hugo:
CREATE USER Louis
WITHOUT LOGIN
GO
CREATE USER Hugo
WITHOUT LOGIN
GO
Note that both of these users are created using the WITHOUT LOGIN
option, meaning that although these users exist in the database, they
are not tied to a SQL Server login and therefore no one can authenticate
as one of them by logging in to the server. This option is one way of
creating the kind of proxy users mentioned previously.
Once the users have been created, create a table owned by Louis:
CREATE TABLE SensitiveData
(
IntegerData INT
)
GO
ALTER AUTHORIZATION ON SensitiveData TO Louis
GO
At this point, Hugo has no
access to the table. To create an access path without granting direct
permissions to the table, a stored procedure could be created, also
owned by Louis:
CREATE PROCEDURE SelectSensitiveData
AS
BEGIN
SET NOCOUNT ON
SELECT *
FROM dbo.SensitiveData
END
GO
ALTER AUTHORIZATION ON SelectSensitiveData TO Louis
GO
Hugo still has no permissions on the table at this point; the user needs to be given permission to execute the stored procedure:
GRANT EXECUTE ON SelectSensitiveData TO Hugo
At this point Hugo
can execute the stored procedure, thereby selecting from the table.
However, this only works because Louis owns both tables, and both are in
the same database; if either of those conditions were not true, the
ownership chain would break, and Hugo would have to be authorized
another way to select from the table. The ownership chain would also
fail if the execution context changed within the stored procedure. For
example, ownership chaining will not work with dynamic SQL.
In the case of a stored
procedure in one database requesting access to an object in another
database, it is possible to maintain an ownership chain, but it gets
quite a bit more complex, and security is much more difficult to
maintain. To set up cross-database ownership chaining,
the user that owns the stored procedure and the referenced table(s)
must be associated with a server-level login, and each database must
have the DB_CHAINING property set using the ALTER DATABASE
command. That property tells SQL Server that either database can
participate in a cross-database ownership chain, either as source or
target—but there is no way to control the direction of the chain, so
setting the option could open up security holes inadvertently.
I recommend that you
avoid cross-database ownership chaining whenever possible, and instead
call stored procedures in the remote database. Doing so will result in a
more secure, more flexible solution. For example, moving databases to
separate servers is much easier if they do not depend on one another for
authentication. In addition, with the inclusion of schemas in SQL
Server 2005, splitting objects into multiple databases is no longer as
important as it once was. Consider avoiding multiple databases
altogether, if at all possible.