Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 20 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
20
Dung lượng
166,81 KB
Nội dung
C H A P T E R 5 PrivilegeandAuthorization 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 privilegeandauthorization 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 PRIVILEGEANDAUTHORIZATION User VS. Application Logins The topics covered in this chapter relate to various privilegeandauthorization 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 PRIVILEGEANDAUTHORIZATION 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 PRIVILEGEANDAUTHORIZATION 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 PRIVILEGEANDAUTHORIZATION 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 PRIVILEGEANDAUTHORIZATION 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 PRIVILEGEANDAUTHORIZATION 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 PRIVILEGEANDAUTHORIZATION 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 CHAPTER 5 PRIVILEGEANDAUTHORIZATION order to return context to your login. The USER_NAME() function can be checked at any time to find out whose context you are executing under. To see the effects of nested impersonation, first be sure to revert back out of Tom’s context, and then create a second user as shown following. The user will be given the right to impersonate Tom, using GRANT IMPERSONATE: CREATE USER Paul WITHOUT LOGIN; GO GRANT IMPERSONATE ON USER::Tom TO Paul; GO If Paul is impersonated, the session will have no privileges to select rows from the TomsData table. In order to get those permissions, Tom must be impersonated from within Paul’s context: EXECUTE AS USER='Paul'; GO --Fails SELECT * FROM TomsData; GO EXECUTE AS USER='Tom'; GO --Succeeds SELECT * FROM TomsData; GO REVERT; GO --Returns 'Paul' -- REVERT must be called again to fully revert SELECT USER_NAME(); GO REVERT; GO The most important thing to understand is that when EXECUTE AS is called, all operations will run as if you are logged in as the impersonated user. You will lose any permissions that the outer user has that the impersonated user does not have, in addition to gaining any permissions that the impersonated user has that the outer user lacks. For logging purposes, it is sometimes important to record the actual logged-in principal. Since both the USER_NAME() function and the SUSER_NAME() function will return the names associated with the impersonated user, the ORIGINAL_LOGIN() function must be used to return the name of the outermost server login. Use of ORIGINAL_LOGIN() will allow you to get the name of the logged-in server principal, no matter how nested their impersonation scope is. 109 CHAPTER 5 PRIVILEGEANDAUTHORIZATION What is a module? Each of the privilege escalation examples that follow use stored procedures to demonstrate a particular element of functionality. However, please be aware that these methods work for any kind of module that SQL Server supports, not just stored procedures. A module is defined as any kind of code container that can be created inside of SQL Server: a stored procedure, view, user-defined function, trigger, or CLR assembly. Ownership Chaining 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 new 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 For this and subsequent examples in this chapter, you should connect to SQL Server using a login that is a member of the sysadmin server role. 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 into 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 110 [...]... used to add to them and create additional flexibility For instance, consider the following two users and associated tables: CREATE USER Kevin WITHOUT LOGIN; GO CREATE TABLE KevinsData 112 CHAPTER 5 PRIVILEGEANDAUTHORIZATION ( SomeData int ); GO ALTER AUTHORIZATION ON KevinsData TO Kevin; GO CREATE USER Hilary WITHOUT LOGIN; GO CREATE TABLE HilarysData ( SomeOtherData int ); GO ALTER AUTHORIZATION ON...CHAPTER 5 PRIVILEGEANDAUTHORIZATION ( 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. .. create secure, granular authorization schemes By keeping authorization layered and following a least -privilege mentality, resources in the database can be made more secure, requiring attackers to do more work in order to retrieve data they are not supposed to access A stored procedure layer can be used to control security, delegating permissions as necessary based on a system of higher-privileged proxy users... 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... ownership chaining and create a stored procedure that is owned by one of the users, but executes under the context of the other The following stored procedure shows how this might look: CREATE PROCEDURE SelectKevinAndHilarysData WITH EXECUTE AS 'Kevin' AS BEGIN SET NOCOUNT ON; SELECT * FROM KevinsData UNION ALL SELECT * FROM HilarysData; END; GO ALTER AUTHORIZATION ON SelectKevinAndHilarysData TO Hilary;... AUTHORIZATION ON SelectKevinAndHilarysData TO Hilary; GO Because Hilary owns the stored procedure, ownership chaining will kick in and allow selection of rows from the HilarysData table But because the stored procedure is executing under the context of the 113 CHAPTER 5 PRIVILEGEANDAUTHORIZATION Kevin user, permissions will also cascade for the KevinsData table In this way, both permission sets can be used,... certificate is that the certificate itself can also be used to propagate permissions granted to the user This is where stored procedure signing comes into play 114 CHAPTER 5 PRIVILEGEANDAUTHORIZATION To illustrate this concept, create a table and grant SELECT access to the Greg user, as follows: CREATE TABLE GregsData ( DataColumn int ); GO GRANT SELECT ON GregsData TO Greg; GO A stored procedure can then... difficult to understand, so it is worth explaining here The sys.crypt_properties view contains information about which modules have been signed by certificates Each certificate has a 32-byte cryptographic hash, its thumbprint, which is used to find out which certificate was used to sign the module, via the sys.certificates view Finally, each database principal 116 CHAPTER 5 PRIVILEGEANDAUTHORIZATION has... the file into the database of your choosing, and from there it can be used to create a database user that will have the same permissions as the server login, by virtue of having been created using the same certificate BACKUP CERTIFICATE alter_db_certificate TO FILE = 'C:\alter_db.cer' WITH PRIVATE KEY ( FILE = 'C:\alter_db.pvk', 117 CHAPTER 5 PRIVILEGEANDAUTHORIZATION ENCRYPTION BY PASSWORD = 'YeTan0tHeR$tRoNGpaSSWoRd?',... MULTI_USER access mode), create a user based on the certificate, and sign the stored procedure with the certificate: CREATE PROCEDURE SetMultiUser AS BEGIN ALTER DATABASE alter_db_example SET MULTI_USER; END; GO CREATE USER alter_db_user FOR CERTIFICATE alter_db_certificate; GO ADD SIGNATURE TO SetMultiUser 118 CHAPTER 5 PRIVILEGEANDAUTHORIZATION BY CERTIFICATE alter_db_certificate WITH PASSWORD = . PRIVILEGE AND AUTHORIZATION User VS. Application Logins The topics covered in this chapter relate to various privilege and authorization scenarios handled. 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