© Peter A. Carter 2016

Peter A. Carter, Securing SQL Server, 10.1007/978-1-4842-2265-2_6

6. Security Metadata

Peter A. Carter

(1)Botley, UK

Although a large amount of security metadata can be viewed from SQL Server Management Studio, there is some metadata that can only be viewed using T-SQL. Even for metadata that can be viewed through the GUI, such as the roles that a database user belongs to, there are times that it is best to use T-SQL; for example, if you need to script an action that you perform on a regular basis, or if you need to review metadata for many principals.

A complete guide to security metadata within SQL Server is worthy of a book in its own right. Therefore, this chapter explains some of the most useful and interesting metadata objects and provides insights into how you may use them.

Security Principal Metadata

When you are implementing, reviewing, or auditing a security policy on an instance, it is likely that you need to retrieve information about many security principals or securable objects. As an example of this, part of your security policy might state that all databases must be owned by the sa account, and you need to verify that this is the case. You could, of course, enter the context menu of each database, select Properties, and then review the Owner field on the General page of the Database Properties dialog box. If the instance hosts 200 databases, however, then this may be a rather tedious and time-consuming task.

Instead of using the GUI, it makes sense to use SQL Server metadata. The database owner of each database can be returned by using the sp_MShasdbaccess stored procedure or by querying the sys.databases catalog view.

The sp_MShasdbaccess stored procedure does not accept parameters; it returns the name and owner of each database, as well as the status of each database.

Tip

The sp_MShasdbaccess procedure only returns rows for databases that the caller has access to. Providing that the procedure is run by a database administrator, this should not be an issue.

To retrieve the data from sys.databases, you need to return the SID (security identifier) of each database by retrieving the owner_sid column and passing this column to the SUSER_SNAME() system function. This is demonstrated in Listing 6-1.

Listing 6-1. Retrieve Database Owners from sys.databases
SELECT name
      ,SUSER_SNAME(owner_sid)
FROM sys.databases ;

The SUSER_SNAME() function accepts a SID as a parameter and returns the login name associated with the SID. If no parameter is passed to the function, then it returns the login name of the caller.

Tip

Many people get confused about the difference between the SUSER_SNAME() function and a very similar function called SUSER_NAME(). They both return a login name. The difference is that SUSER_SNAME() accepts a SID as a parameter. SUSER_NAME() accepts a login id (principal id) as a parameter.

Finding a User’s Effective Permissions

When you have a complex hierarchy of server roles and database roles, as well as permissions granted directly to users, it can sometimes be challenging to work out exactly which permissions a user has. A system function that can help with this issue is sys.fn_my_permissions(). This function accepts the parameters described in Table 6-1.

Table 6-1. sys.fn_my_permissions Parameters

Parameter

Description

securable

The name of the securable that you wish to determine a user’s permissions against.

securable_class

The type of securable that is interrogated; for example, SERVER, DATABASE, or OBJECT.

The function returns the columns described in Table 6-2.

Table 6-2. sys.fn_my_permissions

Column

Description

entity_name

The name of the securable.

subentity_name

If the securable has columns, then subentity_name contains the name of the column; otherwise, it is NULL.

permission_name

The name of the permission assigned to the security principal.

The function is designed to return information about the caller of the function, but you can change this behavior by using the EXECUTE AS statement. The EXECUTE AS statement is used to specify the name of a login or user whose identity should be used as the execution context of the session.

As an example of how the EXECUTE AS statement works, please review Listing 6-2.

Listing 6-2. EXECUTE AS Example
USE master
GO


CREATE LOGIN DemoLogin WITH PASSWORD=N'Pa$$w0rd', CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF

ALTER SERVER ROLE sysadmin ADD MEMBER DemoLogin

USE AdventureWorks2016CTP3
GO


SELECT SUSER_SNAME() ;

EXECUTE AS LOGIN = 'DemoLogin' ;

SELECT SUSER_SNAME() ;

REVERT ;

SELECT SUSER_SNAME() ;

The script returns three results. The first result is your own login name. The second is DemoLogin’s login name. And the third result is your own login again. This is because the REVERT keyword is used to change the session context back to your own security context.

The script in Listing 6-3 demonstrates how the sys.fn_my_permissions function can be used in conjunction with the EXECUTE AS clause to find a user’s effective permissions at the instance, the database, and the object (within the current database) levels in a single query. I first wrote about this technique back in 2011 on the “SQL Server: Down & Dirty” blog ( www.sqlserverdownanddirty.blogspot.com ); since then, the method has been used and replicated by many others.

Caution

If a database uses a different collation to the server, then you may need to use the COLLATE statement within the query to avoid issues with running the script.

Listing 6-3. Find a User’s Effective Permissions
EXECUTE AS LOGIN = 'DemoLogin'
   SELECT o.name
        , a.entity_name
        , a.subentity_name
        , a.permission_name
   FROM sys.objects o
   CROSS APPLY sys.fn_my_permissions(CONCAT(
                                        QUOTENAME(
                                                SCHEMA_NAME(schema_id))
                                     , '.'
                                     , QUOTENAME(o.name))
                                     , 'OBJECT') a  
   UNION ALL
   SELECT d.name
        , a.entity_name
        , a.subentity_name
        , a.permission_name
   FROM sys.databases d
   CROSS APPLY fn_my_permissions(QUOTENAME(d.name), 'DATABASE') a
   UNION ALL
   SELECT @@SERVERNAME COLLATE Latin1_General_CI_AS
          , a.entity_name
          , a.subentity_name
          , a.permission_name
   FROM fn_my_permissions(NULL, 'SERVER') a
   ORDER BY 1
REVERT

The script works by running three separate queries and creating a union of the results. The first query returns each object name from sys.objects and passes this name, along with the schema name, into the sys.fn_my_permissions() function . The second query does the same thing, but instead of interrogating sys.objects, the script interrogates sys.databases to retrieve permissions at the database level. The final query resolves the user’s effective permissions against the instance itself.

Securable Metadata

There are ways in which your security profile may determine that your objects need to be secured. The following sections explore some of these potential requirements and demonstrate how metadata can help you verify or enforce your policy.

Code Signing

Code injection attacks can cause security breaches. You can protect against them by using code signing. For now, however, let’s simply assume that your security policy states that all assemblies and stored procedures must be code signed to help minimize the security footprint.

The script in Listing 6-4 reports which stored procedures in the database have been code signed and if the signature is valid. The script uses two security metadata objects. The first is sys.Certificates. The columns returned by this catalog view are described in Table 6-3.

Table 6-3. sys.Certificates Columns

Column

Description

name

The name of the certificate.

certificate_id

The id of the certificate.

principal_id

The id of the database user that owns the certificate.

pvt_key_encryption_type

The encryption method of the private key. Possible values are as follows:

•   NA: Indicates that there is no private key associated with the certificate.

•   MK: Indicates that encryption is by the database master key.

•   PW: Indicates that encryption is by password.

•   SK: Indicates that encryption is by the service master key.

pvt_key_encryption_type_desc

The textual description of the private key encryption type. Possible values are as follows:

•   NO_PRIVATE_KEY

•   ENCRYPTED_BY_MASTER_KEY

•   ENCRYPTED_BY_PASSWORD

•   ENCRYPTED_BY_SERVICE_MASTER_KEY

is_active_for_begin_dialog

Specifies if the certificate is allowed to be used to begin an encrypted Service Broker conversation.

•   0: Indicates that it is not allowed to start an encrypted Service Broker conversation.

•   1: Indicates that it is allowed to start an encrypted Service Broker conversation.

issuer_name

The name of the authority that issued the certificate.

cert_serial_number

The serial number of the certificate.

sid

The login SID of the certificate.

string_sid

The name of the login SID.

subject

The subject associated with the certificate.

expiry_date

The certificate’s expiry date.

start_date

The certificate’s start date.

thumbprint

The SHA-1 hash of the certificate.

attested_by

Internal use.

pvt_key_last_backup_date

The date and time that the certificate was last backed up.

The second metadata object used by the script is sys.fn_check_object_signatures(). This system function is used to return information regarding object signatures and their validity, based on the thumbprint of a certificate or asymmetric key. The function accepts the parameters described in Table 6-4.

Table 6-4. sys.fn_check_object_signatures Parameters

Parameter

Description

@Class

The type of thumbprint that the function checks. The acceptable values are

•   Certificate

•   Asymmetric key

@Thumbprint

The thumbprint to be checked.

The sys.fn_check_object_signatures function returns the columns described in Table 6-5.

Table 6-5. sys.fn_check_object_signatures Columns

Column

Description

type

The type description of the entity.

entity_id

The object id of the evaluated entity.

is_signed

Denotes if the object is signed or not.

•   0: Indicates that the object is not signed.

•   1: Indicates that the object is signed.

is_signature_valid

Denotes if the object’s signature is valid. If the object is not signed, it returns 0.

•   0: Indicates that either the object is not signed or that the signature is not valid.

•   1: Indicates that the object’s signature is valid.

Listing 6-4. Check Objects’ Signatures
DECLARE @thumbprint VARBINARY(20) ;  

SET @thumbprint =
(
SELECT thumbprint  
FROM sys.certificates  
WHERE name LIKE '%SchemaSigningCertificate%'
) ;  


SELECT entity_id
         , SCHEMA_NAME(o.schema_id) + '.' + OBJECT_NAME(entity_id) AS ProcedureName
         , is_signed
         , is_signature_valid  
FROM sys.fn_check_object_signatures ('certificate', @thumbprint)  cos
INNER JOIN sys.objects o
        ON cos.entity_id = o.object_id
WHERE cos.type = 'SQL_STORED_PROCEDURE ' ;  
GO  

The first part of the script retrieves the thumbprint of the database’s code signing certificate from the sys.Certificates catalog view. The second part of the script passes this thumbprint into the sys.fn_check_object_signatures and joins the results to the sys.objects catalog view to retrieve the schema name of the procedure.

Permissions Against a Specific Table

You may have a specific table or set of tables that contains sensitive information, and your security policy may state that you need to regularly audit who has permissions to that table and who assigned those permissions. Using SQL Server metadata, this is a straightforward task.

The sp_table_privileges system stored procedure identifies all permissions that principals have against a specific table, along with who granted those permissions. The procedure accepts the parameters described in Table 6-6.

Table 6-6. sp_table_privileges Parameters

Parameter

Description

@table_name

The name of the table to report on.

@table_owner

The name of the schema to which the table belongs.

@table_qualifier

The name of the database that hosts the table.

@fUsePattern

Specifies if _, %, [, and ] should be treated as wildcard characters.

•   0 indicates that they should be treated as literals.

•   1 indicates that they should be treated as wildcard characters.

The columns returned by the sp_table_privileges procedure are described in Table 6-7.

Table 6-7. sp_table_privileges Columns

Column

Description

TABLE_QUALIFIER

The database in which the table resides.

TABLE_OWNER

The schema in which the table resides.

TABLE_NAME

The name of the table.

GRANTOR

The security principal that granted the permission.

GRANTEE

The security principal assigned the permission.

PRIVILEGE

The permission that has been assigned.

IS_GRANTABLE

Specifies if the grantee has the WITH GRANT* assignment.

*Please see Chapter 2 for further details

The statement in Listing 6-5 returns results for all tables in the current database.

Listing 6-5. sp_table_privileges
EXEC sp_table_privileges @Table_name = '%' ;

Audit Metadata

As discussed in Chapter 3, SQL Server Audit provides a granular and lightweight method of auditing users’ actions within SQL Server. One of the advantages of SQL Server Audit is that you are able to “audit the audit” in an attempt to avoid non-reputability. For example, if an ill-intending DBA turned off the auditing, while they performed a malicious act, the action itself would not be audited, but the fact that the DBA had turned the audit off and then turned it back on again would be audited.

SQL Server exposes many metadata objects that assist a DBA in his work. One of the objects that I find most useful is the sys.fn_get_audit_file() function. The function returns the contents of a SQL Server Audit file. This can be inserted into a table for further analysis. The function accepts three parameters, which are described in Table 6-8.

Table 6-8. sys.fn_get_audit_file() Parameters

Parameter

Description

file_pattern

The name of the audit file that you wish to read. This path can contain the * wildcard to read multiple files. This is useful when you have rollover files.

initial_file_name

Specifies the path and the name of a specific file in the audit file set where the file read should begin. If not required, pass NULL.

audit_record_offset

Specifies a known location with the file specified for the initial_file_name parameter and begins the file read at this record. If not required, pass NULL.

The sys.fn_get_audit_file() function returns the columns described in Table 6-9.

Table 6-9. sys.fn_get_audit_file() Columns

Column

Description

event_time

The date and time at which the audited event occurred.

sequence_number

A sequence number of records within a single audit entry where the entry was too large to fit inside a buffer and was broken down.

action_id

The id of the action.

succeeded

Specifies if the action that caused the audit event to fire was successful.

•   0: Indicates that the action failed.

•   1: Indicates that the action succeeded.

permission_bitmask

Where appropriate, specifies the permissions that were assigned or revoked.

is_column_permission

Specifies if the permission (in the permission_bitmask column) was a column-level permission.

•   0: Indicates that it was not a column-level permission.

•   1: Indicates that it was a column-level permission.

session_id

The id of the session in which the event occurred.

server_principal_id

The principal id of the login that performed the action, which caused the audit event to fire.

database_principal_id

The principal id of the database user that performed the action, which caused the audit event to fire.

target_server_principal_id

Where applicable, returns the principal id of the login that was subject to a permission assignment or revocation.

target_database_principal_id

Where applicable, returns the principal id of the database user that was subject to a permission assignment or revocation.

object_id

Where applicable, returns the object id of the target object that caused the audit event to fire.

class_type

The type of auditable entity on which the auditable event occurred.

session_server_principal_name

The name of the login that the session was executing in. This is blank if no session was established. For example, where a failed login has been audited

server_principal_name

The name of the login that performed the action, which caused the audit event to fire.

server_principal_sid

The SID of the login that performed the action, which caused the audit event to fire.

database_principal_name

The name of the database user that performed the action, which caused the audit event to fire.

target_server_principal_name

Where applicable, returns the name of the login that was subject to a permission assignment or revocation.

target_server_principal_sid

Where applicable, returns the SID of the login that was subject to a permission assignment or revocation.

target_database_principal_name

Where applicable, returns the name of the database user that was subject to a permission assignment or revocation.

server_instance_name

The serverinstance name of the instance where the audit event occurred

database_name

The name of the database in which the audit event occurred.

schema_name

The schema context in which the audit event occurred.

object_name

The name of the object, which was the subject of the auditable event.

statement

The T-SQL statement that caused the audit event to fire.

additional_information

For some events, an XML document is returned, containing additional information. For example, if a failed login is audited, the additional information includes the IP address that the login attempt originated from.

file_name

The fully qualified name of the audit file.

audit_file_offset

The buffer offset of the audit record, within the file.

user_defined_event_id

When an audit event has been written using sp_audit_write, returns the user defined event id.

user_defined_information

When an audit event has been written using sp_audit_write, returns user defined additional information.

The query in Listing 6-6 returns all records from all audit files stored within the c:audit folder.

Listing 6-6. Read an Audit File
SELECT * FROM sys.fn_get_audit_file('c:audit*',NULL,NULL) ;

Encryption Metadata

Chapter 5 discusses encryption in SQL Server, and as you can imagine, there are a raft of metadata objects that expose information regarding your encryption configuration. The following sections discuss useful metadata that is exposed around Always Encrypted and TDE.

Always Encrypted Metadata

Because there can be a one-to-many relationship between column master keys and column encryption keys, followed by a one-to-many relationship between column encryption keys and encrypted columns, metadata can be invaluable in keeping track of how your data is encrypted. The query in Listing 6-7 joins sys.tables and sys.columns to the new sys.column_encryption_keys, sys.column_encryption_key_values, and sys.column_master_keys catalog views to provide a complete path through the hierarchy from the column to key store location of the column master key.

The sys.column_encryption_keys view returns the columns described in Table 6-10.

Table 6-10. sys.column_encryption_keys Columns

Column

Description

name

The name of the column encryption key.

column_encryption_key_id

The id of the column encryption key.

create_date

The date and time that the key was created.

modify_date

The date and time that the key was last modified.

The sys.column_encryption_key_values view returns the columns described in Table 6-11.

Table 6-11. sys.column_encryption_key_values Columns

Column

Description

column_encryption_key_id

The id of the column encryption key.

column_master_key_id

The id of the column master key that has been used to encrypt the column encryption key.

encrypted_value

The value of the column encryption key, encrypted using the column master key.

encryption_algorithm_name

The algorithm used to encrypt the column encryption key.

* Use this view as an intermediate join between sys.column_encryption_keys and sys.column_master_keys

The sys.column_master_keys view returns the columns described in Table 6-12.

Table 6-12. sys.column_master_keys

Column

Description

name

The name of the column master key.

column_master_key_id

The id of the column master key.

create_date

The date and time that the key was created.

modify_date

The date and time that the key was last modified.

key_store_provider_name

The type of key store that the column master key is stored in.

key_path

The path to the key within the key store.

Listing 6-7 demonstrates how these metadata objects can be drawn together.

Listing 6-7. Interrogate Always Encrypted Metadata
SELECT
          t.name AS TableName
        , c.name AS ColumnName
        , c.encryption_type_desc
        , c.encryption_algorithm_name
        , cek.name AS ColumnEncryptionKeyName
        , cev.encrypted_value
        , cev.encryption_algorithm_name
        , cmk.name as ColumnMasterKeyName
        , cmk.key_store_provider_name AS column_master_key_store_provider_name
        , cmk.key_path
FROM sys.columns c
INNER JOIN sys.column_encryption_keys cek
    ON c.column_encryption_key_id = cek.column_encryption_key_id
INNER JOIN sys.tables t
    ON c.object_id = t.object_id
JOIN sys.column_encryption_key_values cev
    ON cek.column_encryption_key_id = cev.column_encryption_key_id
JOIN sys.column_master_keys cmk
    ON cev.column_master_key_id = cmk.column_master_key_id ;

TDE Metadata

Note

For described information regarding TDE, please refer to Chapter 5.

TDE metadata is exposed through the sys.databases, sys.certificates, and sys.database_encryption_keys catalog views. The sys.databases catalog view contains a column called is_encrypted. This column has the data type of BIT and returns 0 if a database is not encrypted with TDE and 1 if it is encrypted. Information on the certificate used to encrypt the database encryption key is exposed through sys.certificates.

The sys.database_encryption_keys catalog view exposes details of the keys used to encrypt the databases. It returns one row for each database that has a database encryption key associated with it. Table 6-13 details the columns returned by this catalog view.

Table 6-13. sys.database_encryption_keys Columns

Column

Description

database_id

The id of the database that is encrypted using the key.

encryption_state

Specifies the current state of encryption for the database indicated by the database_id column. The following are possible values:

•   0: Indicates that no encryption key is present. You will not see this status under normal operations, because if no key exists, the catalog view does not return a row.

•   1: Indicates that the database is not encrypted. You see this status when TDE has been encrypted, but the database encryption key has not been dropped.

•   2: Indicates that the database is currently being encrypted. You see this status immediately after enabling TDE on a database while the background encryption thread is still running.

•   3: Indicates that the database is encrypted.

•   4: Indicates that a change to the database encryption key is currently in progress.

•   5: Indicates that the database is currently being decrypted. You see this status immediately after turning off TDE for a database, before the background thread completes.

•   6- Indicates that a change to the database encryption key or the server certificate used to encrypt the database encryption key is currently in progress.

create_date

The date and time that the database encryption key was created.

regenerate_date

The date and time that the database encryption key was regenerated.

modify_date

The date and time that the database encryption key was last modified.

set_date

The date and time that the database encryption key was associated with the database.

opened_date

The date and time that the database encryption key was last opened.

key_algorithm

The algorithm used to encrypt the database encryption key.

key_length

The length of the key.

encryptor_thumbprint

The encrypted value of the certificate used to encrypt the database encryption key.

encryptor_type

Indicates the type of encryptor that was used to encrypt the database encryption key. Possible values are

•   ASYMMETRIC KEY

•   CERTIFICATE

percent_complete

If the encryption_state column indicates a status of 2 or 5, this column indicates how far through the encryption or decryption process the background thread is. If the encryption_state column indicates a different status, then this column returns 0.

The metadata exposed for TDE can be useful at various times; for example, to return a list of encrypted database on the instance, use the script in Listing 6-8.

Listing 6-8. Return a List of Encrypted Databases
SELECT name
FROM sys.databases
WHERE is_encrypted = 1 ;

If you need to ensure that all of the server certificates that are used to encrypt database encryption keys have been backed up, you can use the query in Listing 6-9. This query returns a list of certificates used in TDE that have not been backed up.

Listing 6-9. Ensure that Certificates Have Been Backed Up
SELECT
     DB_NAME(dek.database_id) AS DatabaseName
    ,c.name AS CertificateName
FROM AdventureWorks2014.sys.dm_database_encryption_keys dek
INNER JOIN master.sys.certificates c
ON c.thumbprint = dek.encryptor_thumbprint
WHERE c.pvt_key_last_backup_date IS NULL ;

If you had a task of encrypting many databases on an instance, you could even use metadata to create a metadata-driven script that would do the hard work for you. I used this script recently—when a friend of mine mentioned that he had been quoted three months by his DBA team—to encrypt 400+ databases on an instance.

The script in Listing 6-10 firsts creates a server certificate that is used to encrypt the database encryption key for each database. The script then uses the sp_msforeachdb system stored procedure to loop around each database.

Inside the loop, the script first checks to ensure that it is not in the context of a system database, and then checks to ensure that the database has not already been encrypted. This makes the script re-runnable, should you have an issue part way through. After the checks are complete, it creates a database encryption key before enabling TDE.

Listing 6-10. Metadata Driven Encryption Script
USE master                                                
GO


CREATE CERTIFICATE TDECert WITH SUBJECT = 'My DEK Certificate';
GO


EXEC sys.sp_MSforeachdb @command1 = 'USE ?
IF (SELECT DB_ID()) > 4
BEGIN
    IF (SELECT is_encrypted FROM sys.databases WHERE database_id = DB_ID()) = 0
        BEGIN
        CREATE DATABASE ENCRYPTION KEY  
        WITH ALGORITHM = AES_128  
        ENCRYPTION BY SERVER CERTIFICATE TDECert


        ALTER DATABASE ?  
        SET ENCRYPTION ON
        END
END' ;

Securing Metadata

While metadata can prove incredibly useful—not just from the security perspective, but also in every other area of SQL Server administration, it can also prove to be a security hole in its own right. If metadata were accessible to everybody, then an attacker could use it to gain information, regarding the configuration of your instance.

Therefore, most metadata only becomes visible to a user after they have been granted permissions to use the object in some way. For example, if you grant the user Phil the SELECT permission on dbo.MyTable, Phil automatically sees the row within sys.tables and sys.objects that relates to the dbo.MyTable object.

If a user needs to see metadata about an object that they should not have permissions to use in any other way, then the VIEW DEFINITION permission can be granted upon that object. The VIEW DEFINITION permission can also be granted at the scope of a database or an entire instance. At the instance level, the permission VIEW ANY DEFIITION gives complete access to metadata instance-wide. This can be useful when you are creating metadata-driven automated scripts and you wish to apply the principal of least privilege.

There are some metadata objects in which users cannot be automatically granted VIEW DEFINITION permission when other permissions are assigned to the object. This is because the objects sit outside of the permissions structure. Take partitions, for example. Each table can be split across three partitions: one for in-row data, another for LOB (large object) data, and the third for overflow data. There is no way to assign permissions on partitions, because they are not directly accessible.

In these circumstances, the public role has the ability to view the associated metadata, and the VIEW DEFINITION permission does not apply. The metadata objects that are visible to the public role are as follows:

  • sys.partition_functions

  • sys.partition_range_values

  • sys.partition_schemes

  • sys.data_spaces

  • sys.filegroups

  • sys.destination_data_spaces

  • sys.database_files

  • sys.allocation_units

  • sys.partitions

  • sys.messages

  • sys.schemas

  • sys.configurations

  • sys.sql_dependencies

  • sys.type_assembly_usages

  • sys.parameter_type_usages

  • sys.column_type_usages

Risks of Metadata Visibility

Even with the security measures that are in place to protect SQL Server, an attacker may still be able to expose some metadata if the overall security design of your application is weak. For example, imagine that you have a web application that handles security in the application tier and then connects to a SQL Server instance by using a single, highly privileged account.

If the web application is vulnerable to SQL injection, then an attacker could force the execution of the query in Listing 6-11.

Listing 6-11. Forced Information Disclosure
SELECT 1 + name FROM sys.tables

When run against the AdventureWorks2016 database, the query in Listing 6-11 returns the error message shown in Figure 6-1.

A395795_1_En_6_Fig1_HTML.jpg
Figure 6-1. Forced error message

This error message has provided the attacker with the following information:

  • There is a table in the database s ScrapReason.

  • The application is leaking metadata.

  • The application is (probably) running through a highly privileged account.

This information gives an attacker plenty of insight into where to start an attack. For example, if the attacker is correct and the application does run through a single account, then it is likely that there is a user’s table specifying permissions. The attacker could amend his query to filter by tables that contain the wildcard strings %user% or %login%. Once the attacker has this information, he can attack the table specifically and start spoofing user identities!

Tip

The moral of the story is that you should always evaluate the security profile of an application holistically to minimize the risk of attack. Even if your instance is secure, a poorly designed application tier could leave you vulnerable.

Summary

SQL Server exposes a vast amount of metadata. This includes metadata that relates to the security implementation within your instance. This security-related metadata assists a DBA in ensuring that the security policy is met. For example, metadata checks a user’s effective permissions at every level of the hierarchy, checks for modules that have not been code signed, and checks which principals have what permissions to a specific securable.

Useful metadata is also exposed about encryption artifacts. This metadata can be used for a variety of purposes, from auditing the column master key locations of an Always Encrypted implementation to automating a TDE implementation.

Although metadata brings many advantages, it also brings risks. If metadata is exposed, then it launches an attack against SQL Server. This is an even higher risk when an application uses a single, highly privileged user to connect to the database engine.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset