Tải bản đầy đủ (.pdf) (20 trang)

Privilege and Authorization

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (166.81 KB, 20 trang )

C H A P T E R 5

  

Privilege and Authorization
SQL Server security is a broad subject area, with enough potential avenues of exploration that entire
books have been written on the topic. This chapter’s goal is not to cover the whole spectrum of security
knowledge necessary to create a product that is secure from end to end, but rather to focus on those
areas that are most important during the software design and development process.
Broadly speaking, data security can be broken into two areas:
• Authentication: The act of verifying the identity of a user of a system
• Authorization: The act of giving a user access to the resources that a system
controls
These two realms can be delegated separately in many cases; so long as the authentication piece
works properly, the user can be handed off to authorization mechanisms for the remainder of a session.
SQL Server authentication on its own is a big topic, with a diverse range of subtopics including
network security, operating system security, and so-called surface area control over the server. While
production DBAs should be very concerned with these sorts of issues, authentication is an area that
developers can mostly ignore. Developers need to be much more concerned with what happens after
authentication: that is, how the user is authorized for data access and how data is protected from
unauthorized users.
This chapter introduces some of the key issues of data privilege and authorization in SQL Server
from a development point of view. Included here is an initial discussion on privileges and general
guidelines and practices for securing data using SQL Server permissions. A related security topic is that
of data encryption, which is covered in detail in the next chapter.
Note that although authentication issues are generally ignored in these pages, you should try to not
completely disregard them in your day-to-day development work. Development environments tend to
be set up with very lax security in order to keep things simple, but a solid development process should
include a testing phase during which full authentication restrictions are applied. This helps to ensure
that rollout to a production system does not end in spectacular failure in which users aren’t even able to
log in!













101
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
User VS. Application Logins
The topics covered in this chapter relate to various privilege and authorization scenarios handled within
SQL Server itself. However, in many database application designs, authorization is handled in the
application layer rather than at the database layer. In such applications, users typically connect and log
into the application using their own personal credentials, but the application then connects to the database
using a single shared application login. This login is given permission to execute all of the stored
procedures in the database related to that application, and it is up to authorization routines in the
application itself to determine those actions that can be performed by any given user.
There are some benefits to using this approach, such as being able to take advantage of connection
pooling between different sessions. However, it means that any features provided by SQL Server to handle
per-user security do not apply. If a bug were to exist in the application, or if the credentials associated with
the application login were to become known, it would be possible for users to execute any queries against
the database that the application had permission to perform.
For the examples in this chapter, I assume a scenario in which users are connecting to the database using
their own personal credentials.
The Principle of Least Privilege
The key to locking down resources in any kind of system—database or otherwise—is quite simple in

essence: any given user should have access to only the bare minimum set of resources required, and for
only as much time as access to those resources is needed. Unfortunately, in practice this is more of an
ideal goal than an actual prescription for data security; many systems do not allow for the set of
permissions allocated to a user to be easily escalated dynamically, and the Microsoft Windows family of
operating systems have not historically been engineered to use escalation of privilege as a means by
which to gain additional access at runtime.
Many multiuser operating systems implement the ability to impersonate other users when access to
a resource owned by that user is required. Impersonation is slightly different than reauthentication;
instead of logging out and resending credentials, thereby forcing any running processes to be stopped,
impersonation allows a process to temporarily escalate its privileges, taking on the rights held by the
impersonated principal. The most common example of this at an operating system level is UNIX’s su
command, which allows a user to temporarily take on the identity of another user, easily reverting back
when done. Windows systems can also handle some degree of impersonation, such as provided by the
.NET WindowsIdentity class.
Permissions in Windows systems are typically provided using access control lists (ACLs). Granting
permission to a resource means adding a user to the list, after which the user can access the resource
again and again, even after logging in and out of the system. This kind of access control provides no
additional security if, for instance, an attacker takes over an account in the system. By taking control of
an account, the attacker automatically has full access to every resource that the account has permission
to access.
By controlling access with impersonation, the user is required to effectively request access to the
resource dynamically, each time access is required. In addition, rights to the resource will only be
maintained during the course of impersonation. Once the user reverts (i.e., turns off impersonation), the
additional access rights are no longer granted. In effect, this means that if an account is compromised,
102
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
the attacker will akso have to compromise the impersonation context in order to gain access to more
secure resources.
The idea of security through least privilege involves creating users with few or no permissions, and
allowing them to briefly escalate their privileges when greater access is required. This is generally

implemented using proxies—users (or other security principals) that have access to a resource but
cannot be authenticated externally. Use of low-privileged external users together with higher-privileged
proxy users provides a buffer against attack, due to the fact that the only accounts that an attacker can
directly compromise from the outside have no permissions directly associated with them. Accessing
more valuable resources requires additional work on the part of the attacker, giving you that much more
of a chance to detect problems before they occur.
Creating Proxies in SQL Server
SQL Server 2008 allows creation of security principals at both the server-level and database-level that
can be used via proxy.
• At the server level, proxy logins can be created that cannot log in.
• At the database level, proxy users can be created that are not associated with a
login.
The only way to switch into the execution context of either of these types of proxy principals is via
impersonation, which makes them ideal for privilege escalation scenarios.
Server-Level Proxies
In order to create a proxy login (which can be used to delegate server-level permissions such as BULK
INSERT or ALTER DATABASE), you must first create a certificate in the master database. Certificates are
covered in more detail in Chapter 6, but for now think of a certificate as a trusted way to verify the
identity of a principal without a password. The following syntax can be used to create a certificate in
master. (Note that before a certificate can be created in any database, a master key must be created.
Again, see Chapter 6.)
USE master;
GO

CREATE CERTIFICATE Dinesh_Certificate
ENCRYPTION BY PASSWORD = 'stR0n_G paSSWoRdS, pLE@sE!'
WITH SUBJECT = 'Certificate for Dinesh';
GO
Once the certificate has been created, a proxy login can be created using the CREATE LOGIN FROM
CERTIFICATE syntax as follows:

CREATE LOGIN Dinesh
FROM CERTIFICATE Dinesh_Certificate;
GO
This login can be granted permissions, just like any other login. However, to use the permissions,
the login must be mapped to a database user. This is done by creating a user using the same certificate
103
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
that was used to create the login, using the CREATE USER FOR CERTIFICATE syntax. See the section “Stored
Procedure Signing Using Certificates” later in this chapter for more information on how to use a proxy
login for server-level permissions.
Database-Level Proxies
Proxy principals that operate at the database level can be created by adding a user to the database that is
not associated with a server login. This is done using CREATE USER WITHOUT LOGIN, as shown in the
following code listing:
CREATE USER Bob
WITHOUT LOGIN;
GO
This user, like any database user, can be assigned ownership and other permissions. However, it is
impossible to log into the server and authenticate as Bob. Instead, you must log in using a valid server-
level login and authenticate to the database with whatever database user is associated with your login.
Only then can you impersonate Bob, taking on whatever permissions the user is assigned. This is
discussed in detail in the section “Basic Impersonation Using EXECUTE AS” later in this chapter.
Data Security in Layers: The Onion Model
Generally speaking, the more levels that an attacker must penetrate in order to access a valuable
resource, the better the chance of being able to prevent their attack. Developers should strive to
construct multiple layers of protection for any sensitive data, in order to ensure that if one security
measure is breached, other obstacles will keep an attacker at bay.
The first layer of defense is everything outside of the database server, all of which falls into the realm
of authentication. Once a user is authenticated, SQL Server’s declarative permissions system kicks in,
and a login is authorized to access one or more databases, based on user mappings.

From there, each user is authorized to access specific resources in the database. Another layer that
can be added for additional security here is use of stored procedures. By assigning permissions only via
stored procedures, it is possible to maintain greater control over when and why escalation should take
place—but more on that will be covered later in this chapter.
Of course, the stored procedure itself must have access to whatever tables and columns are
required, and these resources can be further locked down if necessary, using encryption or row-level
security schemes.
Figure 5-1 shows some of the layers that should be considered when defining a SQL Server security
scheme, in order to maximize the protection with which sensitive data is secured. The remainder of this
chapter deals primarily with how best to control access to resources using stored procedures as the
primary access layer into the data once a user is authenticated.
A stored procedure layer provides an ideal layer of abstraction between data access methods and
the data itself, allowing for additional security to be programmed in via parameters or other inline logic.
For instance, it is trivial to log every access to sensitive data via a stored procedure, by including logging
code in the procedure. Likewise, a stored procedure might be used to force users to access data on a
granular basis by requiring parameters that are used as predicates to filter data. These security checks
are difficult or impossible to force on callers without using stored procedures to encapsulate the data
access logic.
104
CHAPTER 5  PRIVILEGE AND AUTHORIZATION

Figure 5-1. Layering security provides multiple levels of protection against attack.
Data Organization Using Schemas
SQL Server 2008 supports ANSI standard schemas, which provide a method by which tables and other
objects can be segmented into logical groups. Schemas are essentially containers into which any
database object can be placed, and certain actions or rules applied en masse to every item in the
schema. This makes tasks such as managing authorization considerably easier since, by dividing your
database into schemas, you can easily group related objects and control permissions without having to
worry about what objects might be added or removed from that collection in the future. As new objects
are added to a schema, existing permissions propagate, thereby allowing you to set up access rights for a

given schema once, and not have to manipulate them again as the database changes.
To create a schema, use the CREATE SCHEMA command. The following T-SQL creates a schema called
Sales:
CREATE SCHEMA Sales;
GO
Optionally you can specify a schema owner by using the AUTHORIZATION clause. If an owner is not
explicitly specified, SQL Server will assign ownership to the user that creates the schema.
Once a schema is created, you can begin creating database objects within the schema, using two-
part naming as follows:
CREATE TABLE Sales.SalesData
(
SaleNumber int,
SaleDate datetime
);
GO
If an object belongs to a schema, then it must be referenced with its associated schema name; so to
select from the SalesData table, the following SQL is used:
105
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
SELECT *
FROM Sales.SalesData;
GO
 Caution In previous versions of SQL Server, references to tables were prefixed with the name of their owner
(e.g.,
Owner.SalesData
). This syntax is deprecated, and two-part naming in SQL Server 2008 references a
schema rather than an object owner.
The beauty of schemas becomes obvious when it is time to apply permissions to the objects in the
schema. Assuming that each object should be treated identically from a permissions point of view, only
a single grant is necessary to give a user access to every object within a schema. For instance, after the

following T-SQL is run, the Alejandro user will have access to select rows from every table in the Sales
schema, even if new tables are added later:
CREATE USER Alejandro
WITHOUT LOGIN;
GO

GRANT SELECT ON SCHEMA::Sales
TO Alejandro;
GO
It’s important to note that, when initially created, the owner of any object in a schema will be the
same as the owner of the schema itself. The individual object owners can be changed later, but in most
cases I recommend that you keep everything in any given schema owned by the same user. This is
especially important for ownership chaining, covered later in this chapter. To explicitly set the owner of
an object requires the ALTER AUTHORIZATION command, as shown in the following T-SQL:
--Create a user
CREATE USER Javier
WITHOUT LOGIN;
GO

--Create a table
CREATE TABLE JaviersData
(
SomeColumn int
);
GO

--Set Javier as the owner of the table
ALTER AUTHORIZATION ON JaviersData
TO Javier;
GO

106
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
As a final note on schemas, there is also a command that can be used to move objects between
them. By using ALTER SCHEMA with the TRANSFER option, you can specify that a table should be moved to
another schema:
--Create a new schema
CREATE SCHEMA Purchases;
GO

--Move the SalesData table into the new schema
ALTER SCHEMA Purchases
TRANSFER Sales.SalesData;
GO

--Reference the table by its new schema name
SELECT *
FROM Purchases.SalesData;
GO
Schemas are a powerful feature, and I recommend that you consider using them any time you’re
dealing with sets of tables that are tightly related to one another. Legacy database applications that use
multiple databases in order to create logical boundaries between objects might also benefit from
schemas. The multiple databases can be consolidated to a single database that uses schemas. The
benefit is that the same logical boundaries will exist, but because the objects are in the same database,
they can participate in declarative referential integrity and can be backed up together.
Basic Impersonation Using EXECUTE AS
Switching to a different user’s execution context has long been possible in SQL Server, using the SETUSER
command, as shown in the following code listing:
SETUSER 'Alejandro';
GO
To revert back to the previous context, call SETUSER again without specifying a username:


SETUSER;
GO

The SETUSER command is only available to members of the sysadmin or db_owner roles (at the server and
database levels, respectively), and is therefore not useful for setting up least-privilege scenarios.
Furthermore, although still implemented by SQL Server 2008, the Microsoft Books Online
documentation states that SETUSER may not be supported in future versions of SQL Server, and
recommends usage of the EXECUTE AS command instead.
The EXECUTE AS command can be used by any user, and access to impersonate a given user or
server login is controlled by a permissions setting rather than a fixed role. The other benefit over SETUSER
is that EXECUTE AS automatically reverts to the original context at the end of a module. SETUSER, on the
other hand, leaves the impersonated context active when control is returned to the caller. This means
that it is impossible to encapsulate impersonation within a stored procedure using SETUSER and
guarantee that the caller will not be able to take control of the impersonated credentials.
107
CHAPTER 5  PRIVILEGE AND AUTHORIZATION
To show the effects of EXECUTE AS, start by creating a new user and a table owned by the user:
CREATE USER Tom
WITHOUT LOGIN;
GO

CREATE TABLE TomsData
(
AColumn int
);
GO

ALTER AUTHORIZATION ON TomsData TO Tom;
GO

Once the user is created, it can be impersonated using EXECUTE AS, and the impersonation context
can be verified using the USER_NAME() function:
EXECUTE AS USER = 'Tom';
GO

SELECT USER_NAME();
GO
 Note In order to use the
EXECUTE AS
statement to impersonate another user or login, a user must have been
granted
IMPERSONATE
permissions on the specified target.
The SELECT statement returns the value Tom, indicating that this is the currently impersonated user.
Any action performed after running EXECUTE AS will use Tom’s credentials. For example, the user can
alter the TomsData table, since Tom owns the table. However, an attempt to create a new table will fail,
since Tom does not have permission to do so:
--This statement will succeed
ALTER TABLE TomsData
ADD AnotherColumn datetime;
GO

--This statement will fail with CREATE TABLE PERMISSION DENIED
CREATE TABLE MoreData
(
YetAnotherColumn int
);
GO
Once you have completed working with the database in the context of Tom’s permissions, you can
return to the outer context by using the REVERT command. If you have impersonated another user inside

of that context (i.e., called EXECUTE AS more than once), REVERT will have to be called multiple times in
108

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×