MSSQL Security

The following section provides guidance for security hardening MS-SQL Database Instances. It highlights how the recommendations tie-in with PCI compliance.

2.2 Develop configuration standards for all system components. Assure that these standards address all known security vulnerabilities and are consistent with industry-accepted system hardening standards. Sources of industry-accepted system hardening standards may include, but are not limited to: • Center for Internet Security (CIS) • International Organization for Standardization (ISO) • SysAdmin Audit Network Security (SANS) Institute • National Institute of Standards Technology (NIST).

Patching & Upgrades

Single Function Servers

PCI DSS Requirements v3.22.2.1 Implement only one primary function per server to prevent functions that require different security levels from co-existing on the same server. (For example, web servers, database servers, and DNS should be implemented on separate servers.)Note: Where virtualization technologies are in use, implement only one primary function per virtual system component.

SQL Server should be installed on a dedicated server... i.e. it should not share with IIS or application code.

Note that this requirement does not preclude databases for different services being hosted in the same SQL Server instance.

Surface Area Reduction

PCI DSS Requirements v3.22.2.2 Enable only necessary services, protocols, daemons, etc., as required for the function of the system.2.2.5 Remove all unnecessary functionality, such as scripts, drivers, features, subsystems, file systems, and unnecessary web servers.

Ad Hoc Distributed Queries

Enabling Ad Hoc Distributed Queries allows users to query data and execute statements on external data sources.

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'Ad Hoc Distributed Queries';

Enable

sp_configure 'show advanced options', 1; 

RECONFIGURE; 

GO 

sp_configure 'Ad Hoc Distributed Queries', 1; 

RECONFIGURE; 

GO

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'Ad Hoc Distributed Queries', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

Bibliography


https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/ad-hoc-distributed-queries-server-configuration-option

CLR (Common Language Runtime)

Cross DB Ownership Chaining

Enabling Cross DB Ownership Chaining allows a member of the db_owner role to gain access to objects owned by a login an another database.

This is Disabled by default. Do not enable at instance level, enable only for specific databases as necessary and only when fully justified.

Check

SELECT name, 

      CAST(value as int) as value_configured, 

      CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'cross db ownership chaining';

If disabled, both values will show 0

Disable

EXECUTE sp_configure 'cross db ownership chaining', 0; 

RECONFIGURE; 

GO

Bibliography

https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/cross-db-ownership-chaining-server-configuration-option

Database Mail XPs

Enabling Databse Mail XPs allows the ability to generate and transmit email messages from SQL Server

This is Disabled by default. Enable only if fully justified.

https://www.brentozar.com/archive/2021/12/dont-use-sql-server-to-send-emails/

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'Database Mail XPs';

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'Database Mail XPs', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

SQL Mail XPs

NOTE: SQL Mail is deprecated in favor of Database Mail. See also: Database Mail XPs

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'SQL Mail XPs';

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'SQL Mail XPs', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; R

ECONFIGURE;

Bibliography


https://msdn.microsoft.com/en-us/library/ms190755(v=sql.105).aspxhttps://msdn.microsoft.com/en-us/library/ms190755(v=sql.100).aspx

Ole Automation Procedures

Check

SELECT name, 

      CAST(value as int) as value_configured, 

      CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'Ole Automation Procedures';

or

EXEC sp_configure 'Ole Automation Procedures'; 

GO 

Enable

sp_configure 'show advanced options', 1; 

GO 

RECONFIGURE; 

GO 

sp_configure 'Ole Automation Procedures', 1; 

GO 

RECONFIGURE; 

GO 

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'Ole Automation Procedures', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

Bibliography


https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/ole-automation-procedures-server-configuration-option

Remote Access


NOTE: This feature will be removed in the next version of Microsoft SQL Server. Do not use this feature in new development work, and modify applications that currently use this feature as soon as possible. Use sp_addlinkedserver instead.NOTE: The remote access option only applies to servers that are added by using sp_addserver, and is included for backward compatibility.

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'remote access';

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'remote access', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

This setting does not take effect until you restart SQL Server.

Bibliography


https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-remote-access-server-configuration-option

Remote Admin Connections

Scan For Startup Procs


NOTE: This setting will be set automatically if you use sp_procoption, which is used to mark or unmark automatically run stored procedures.NOTE: Replication requires this setting to be enabled and will automatically change this setting if needed.

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'scan for startup procs';

If both values are 0 then this option is disabled.

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'scan for startup procs', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;


NOTE: changing this setting to 0 will prevent Replication and certain audit traces and other commonly used monitoring SPs from re-starting on start up.  I.e. if this setting is enabled it is likely to be because something needs it; check carefully before disabling.

Bibliography


https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-scan-for-startup-procs-server-configuration-option

Trustworthy

Check

SELECT name 

FROM sys.databases 

WHERE is_trustworthy_on = 1 

AND name != 'msdb'; 

Disable

ALTER DATABASE [<database_name>] SET TRUSTWORTHY OFF;

Repeat for all databases except MSDB

Bibliography


https://docs.microsoft.com/en-us/sql/relational-databases/security/trustworthy-database-propertyhttps://support.microsoft.com/it-it/help/2183687/guidelines-for-using-the-trustworthy-database-setting-in-sql-server

Network Protocols

Bibliography


https://msdn.microsoft.com/en-us/library/ms191294(v=sql.105).aspxhttps://msdn.microsoft.com/en-us/library/ms191294(v=sql.100).aspxhttps://msdn.microsoft.com/en-us/library/dd206997(v=sql.105).aspx (How to: Enable or Disable a Server Network Protocol (PowerShell)

Hide Instance


NOTE: This option is not appropriate for clustered instances. If you hide a clustered named instance, the cluster service may not be able to connect to the SQL Server. 

Check

DECLARE @getValue INT; 

EXEC master..xp_instance_regread 

      @rootkey = N'HKEY_LOCAL_MACHINE', 

      @key = N'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQLServer\SuperSocketNetLib', 

      @value_name = N'HideInstance', 

      @value = @getValue OUTPUT; 

SELECT @getValue;

A return value of 1 indicates that the instance i hidden.


You can also check in SSCM (SQL Server Configuration Manager)...Expand SQL Server Network Configuration, right-click Protocols for,<server instance>., then select Properties...

Enable

EXEC master..xp_instance_regwrite 

      @rootkey = N'HKEY_LOCAL_MACHINE', 

      @key = N'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQLServer\SuperSocketNetLib', 

      @value_name = N'HideInstance', 

      @type = N'REG_DWORD', 

      @value = 1;

You can also change the value using the SSCM Window shown in the Check section above.

Bibliography


https://msdn.microsoft.com/en-us/library/ms179327(v=sql.105).aspxhttps://msdn.microsoft.com/en-us/library/ms179327(v=sql.100).aspx

'sa' Login Account

xp_cmdshell

Check

SELECT name, 

       CAST(value as int) as value_configured, 

       CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'xp_cmdshell';

If both values re 0 then this option is disabled.

Disable

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'xp_cmdshell', 0; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

Bibliography


https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/xp-cmdshell-transact-sqlhttps://docs.microsoft.com/en-us/sql/database-engine/configure-windows/xp-cmdshell-server-configuration-option
PCI DSS Requirements v3.22.1 Always change vendor-supplied defaults and remove or disable unnecessary default accounts before installing a system on the network. This applies to ALL default passwords, including but not limited to those used by operating systems, software that provides security services, application and system accounts, point-of-sale (POS) terminals, payment applications, Simple Network Management Protocol (SNMP) community strings, etc.).PCI DSS Requirements v3.22.2.2 Enable only necessary services, protocols, daemons, etc., as required for the function of the system.

Non-Standard Ports


NOTE: Changing the port has little effect on security. You are better off:
  • Not exposing the SQL Server instance to the internet
  • Making sure you are fully patched.
  • Limiting database access to your API only. Make sure the API can't do more than it needs to.

NOTE: Use extreme caution when changing port on an established database server. 

Because port 1433 is the known standard for SQL Server, some organizations specify that the SQL Server port number should be changed to enhance security. This might be helpful in some environments. However, the TCP/IP architecture permits a port scanner to query for open ports, so changing the port number is not considered a robust security measure..(1)

To see which port your instance is currently listening on...

DECLARE @value nvarchar(256);

EXECUTE master.dbo.xp_instance_regread

N'HKEY_LOCAL_MACHINE',

N'SOFTWARE\Microsoft\Microsoft SQL Server\MSSQLServer\SuperSocketNetLib\Tcp\IPAll',

N'TcpPort',

@value OUTPUT,

N'no_output';

SELECT @value AS TCP_Port

If SQL Server is configured to use Dynamic Port numbering, use this script instead...

DECLARE @portNo NVARCHAR(10)

EXEC xp_instance_regread

@rootkey = 'HKEY_LOCAL_MACHINE',

@key =

'Software\Microsoft\Microsoft SQL Server\MSSQLServer\SuperSocketNetLib\Tcp\IpAll',

@value_name = 'TcpDynamicPorts',

@value = @portNo OUTPUT

SELECT [PortNumber] = @portNo

GO

Alternatively use following script

SELECT distinct local_tcp_port

FROM   sys.dm_exec_connections

WHERE  net_transport = 'TCP'

Change Port


(1) https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-a-server-to-listen-on-a-specific-tcp-port

Bibliography

(1) https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-a-server-to-listen-on-a-specific-tcp-porthttps://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtmlhttps://bornsql.ca/blog/dont-change-your-default-sql-server-port-for-security-reasons/
https://sqldbpool.com/2014/12/02/t-sql-script-to-check-sql-server-instance-tcpip-port-number/

Authentication and Authorization

PCI DSS Requirements v3.2Requirement 2: Do not use vendor-supplied defaults for system passwords and other security parameters2.2 Develop configuration standards for all system components2.2.4 Configure system security parameters to prevent misuse.
PCI DSS Requirements v3.2Requirement 8: Assign a unique ID to each person with computer access8.1 Define and implement policies and procedures to ensure proper user identification management for non-consumer users and administrators on all system components8.1.6 Limit repeated access attempts by locking out the user ID after not more than six attempts.

Server Authentication

There are two types of Server Authentication...

The default is Windows Authentication Mode. Enable SQL Server Authentication only if fully justified.

The CIS Microsoft SQL Server 2019 Benchmark considers this a Level 1 requirement with this rationale...

"Windows provides a more robust authentication mechanism than SQL Server authentication."

The CIS benchmark also suggests use of a Centralized Point of Authentication. For SQL Server this would generally mean using Windows Authentication Mode in combination with Active Directory users rather than local Windows accounts...

"Configure access for all accounts through as few centralized points of authentication as possible, including network, security, and cloud systems."

Check

SELECT SERVERPROPERTY('IsIntegratedSecurityOnly') as [login_mode]; 

A login mode 0f 1 indicates Windows Authentication ModeA login mode of 0 indicates Mixed Mode

Set

USE [master] 

GO 

EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'LoginMode', REG_DWORD, 1 

GO

This method requires the SQL Server Service to be restarted for the change to take effect.
This can also be set from SSMS (SQL Server Management Studio)...In the Object Explorer pane, right-click the instance name and select Properties then select the Security page...

Bibliography


https://msdn.microsoft.com/en-us/library/ms188470(v=sql.100).aspxhttps://msdn.microsoft.com/en-us/library/ms188470(v=sql.105).aspx

 GUEST Connect

Check

USE [<database_name>]; 

GO 

SELECT DB_NAME() AS DatabaseName, 'guest' AS Database_User, [permission_name], [state_desc] 

FROM sys.database_permissions 

WHERE [grantee_principal_id] = DATABASE_PRINCIPAL_ID('guest') 

AND [state_desc] LIKE 'GRANT%' 

AND [permission_name] = 'CONNECT' 

AND DB_NAME() NOT IN ('master','tempdb','msdb');

REVOKE

USE [<database_name>]; 

GO 

REVOKE CONNECT FROM guest;

Bibliography

https://docs.microsoft.com/en-us/sql/relational-databases/policy-based-management/guest-permissions-on-user-databases

Orphaned Users

A database user for which the corresponding SQL Server login is undefined or is incorrectly defined on a server instance cannot log in to the instance and is referred to as orphaned and should be removed.

Check

USE [<database_name>]; 

GO 

EXEC sp_change_users_login @Action='Report';

go


SELECT dp.type_desc, dp.SID, dp.name AS user_name  

FROM sys.database_principals AS dp  

LEFT JOIN sys.server_principals AS sp ON dp.SID = sp.SID  

WHERE sp.SID IS NULL  

  and dp.name NOT IN ('guest', 

                        'INFORMATION_SCHEMA',

                        'sys',

                        'MS_DataCollectorInternalUser')

  and dp.type_desc <> 'DATABASE_ROLE' 

--For each database

create table #_tmp (db varchar(50), type_desc varchar(25), uname varchar(255))

DECLARE @command varchar(1000) 


SELECT @command = 'USE [?] select db_name() as db, dp.type_desc, dp.name AS user_name

FROM sys.database_principals AS dp  

LEFT JOIN sys.server_principals AS sp  

    ON dp.SID = sp.SID  

WHERE sp.SID IS NULL  

    and dp.name NOT IN (''guest'',

                        ''INFORMATION_SCHEMA'',

                        ''sys'',

                       ''MS_DataCollectorInternalUser'')

and dp.type_desc <> ''DATABASE_ROLE''' 

insert into #_tmp EXEC sp_MSforeachdb @command 


select * from #_tmp

drop table #_tmp

Remove

DROP USER

Bibliography

https://msdn.microsoft.com/en-us/library/ms175475(v=sql.100).aspxhttps://msdn.microsoft.com/en-us/library/ms175475(v=sql.105).aspx

User - MSSQL Service Account

Check

User - SQLAgent Service Account

The SQLAgent Service Account should own the SQL Agent Services

The service account (in case of a local or AD account) and service SID should not be members of the Windows Administrators group. 

To check..

Service Account - Full-Text

NOTE: The service account and/or service SID used by the MSSQLFDLauncher service for a default instance or MSSQLFDLauncher$ service for a named instance should not be a member of the Windows Administrator group either directly or indirectly (via a group). This also means that the account known as LocalSystem (aka NT AUTHORITY\SYSTEM) should not be used for the Full-Text service as this account has higher privileges than the SQL Server service requires.

By default, the Service Account (or Service SID) is not a member of the Administrators group

To address this...

In the case where LocalSystem is used, use SQL Server Configuration Manager to change to a less privileged account. Otherwise, remove the account or service SID from the Administrators group. You may need to run the SQL Server Configuration Manager if underlying permissions had been changed or if SQL Server Configuration Manager was not originally used to set the service account.

Role - PUBLIC

The public role is a special fixed server role containing all logins.

By default, the public server role is granted VIEW ANY DATABASE permission and the CONNECT permission on the default endpoints (TSQL Local Machine, TSQL Named Pipes, TSQL Default TCP, TSQL Default VIA). The VIEW ANY DATABASE permission allows all logins to see database metadata, unless explicitly denied.

Default Permissions

Any permissions granted to this role will be available to all logins.

Therefore in almost all scenarios any Grants would be better made to individual users or user-defined Roles.

To check if any extra permissions have been granted to the public server role...

SELECT * 

FROM master.sys.server_permissions 

WHERE (grantee_principal_id = SUSER_SID(N'public') and state_desc LIKE 'GRANT%') 

AND NOT (state_desc = 'GRANT' and [permission_name] = 'VIEW ANY DATABASE' and class_desc = 'SERVER') 

AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 2) 

AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 3) 

AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 4) 

AND NOT (state_desc = 'GRANT' and [permission_name] = 'CONNECT' and class_desc = 'ENDPOINT' and major_id = 5);

The query should not return any rows. Any rows returned are extra permissions that you should consider revoking...

USE [master] 

GO 

REVOKE <permission_name> FROM public; 

GO

SQL Agent Proxies

The PUBLIC role, by default, does not have access to any proxy. Granting access to SQL Agent proxies for the public role would allow all users to utilize the proxy which may have high privileges. This would likely break the principle of least privileges.

To check if access to any proxies has been granted to the msdb databases's public role...

USE [msdb] 

GO 

SELECT sp.name AS proxyname 

FROM dbo.sysproxylogin spl 

JOIN sys.database_principals dp 

ON dp.sid = spl.sid 

JOIN sysproxies sp 

ON sp.proxy_id = spl.proxy_id 

WHERE principal_id = USER_ID('public'); 

GO

To revoke access...

Use sp_grant_login_to_proxy to explicitly grant access to the proxy to the required security principals then...

USE [msdb] 

GO 

EXEC dbo.sp_revoke_login_from_proxy @name = N'public', @proxy_name = N''; 

GO

Bibliography

https://support.microsoft.com/en-us/help/2160741/best-practices-in-configuring-sql-server-agent-proxy-account

SQL Logins

Windows BUILTIN Groups

The Windows BUILTIN Groups should not be used as logins for SQL Server instances.

The BUILTIN groups (Administrators, Everyone, Authenticated Users, Guests, etc) generally contain very broad memberships which would not meet the best practice of ensuring only the necessary users have been granted access to a SQL Server instance. These groups should not be used for any level of access into a SQL Server Database Engine instance.

By default, no BUILTIN groups are added as SQL Logins. 

To check if any BUILTIN groups are added as SQL Logins...

SELECT pr.[name], pe.[permission_name], pe.[state_desc] 

FROM sys.server_principals pr 

JOIN sys.server_permissions pe 

ON pr.principal_id = pe.grantee_principal_id 

WHERE pr.name like 'BUILTIN%';

To fix this...

USE [master] 

GO 

DROP LOGIN [BUILTIN\<name>] 

GO

Local Windows Groups

Local Windows groups should not be used as logins for SQL Server instances.

Allowing local Windows groups as SQL Logins provides a loophole whereby anyone with OS level administrator rights (and no SQL Server rights) could add users to the local Windows groups and thereby give themselves or others access to the SQL Server instance.

By Default, no local groups are added as SQL Logins.

To check if any local groups have been added as SQL Server Logins...

USE [master] 

GO 

SELECT pr.[name] AS LocalGroupName, pe.[permission_name], pe.[state_desc] 

FROM sys.server_principals pr 

JOIN sys.server_permissions pe ON pr.[principal_id] = pe.[grantee_principal_id] 

WHERE pr.[type_desc] = 'WINDOWS_GROUP' 

AND pr.[name] like CAST(SERVERPROPERTY('MachineName') AS nvarchar) + '%';

To fix this...

USE [master] 

GO 

DROP LOGIN [<name>] 

GO

NT AUTHORITY\SYSTEM

In earlier versions of SQL Server, NT AUTHORITY\SYSTEM was granted the sysadmin role. This is no longer recommended as it is considered a shared account.

https://www.stigviewer.com/stig/ms_sql_server_2016_instance/2018-03-09/finding/V-79129
PCI DSS Requirements v3.2Requirement 8: Assign a unique ID to each person with computer access8.1 Define and implement policies and procedures to ensure proper user identification management for non-consumer users and administrators on all system components8.1.8 If a session has been idle for more than 15 minutes, require the user to re-authenticate to re-activate the terminal or session.

Expiring Sessions

To expire a session that has been idle for more than 15 minutes... 

https://docs.microsoft.com/en-gb/archive/blogs/sql_server_isv/expiring-sessions-after-15-minutes-on-sql-server

Create the following procedure and schedule it to be executed every minute by a SQL Server Agent Job...

CREATE PROC p_SessionTimeOut

AS

SET NOCOUNT ON

DECLARE @Now DATETIME

DECLARE @Cmd nvarchar(40)

DECLARE @SpId int

SET @Now = GetDate()

CREATE TABLE #Who2(

    [SPID] int, 

    [Status] SysName NULL,

    [Login] SysName NULL, 

    [HostName] SysName NULL,

    [BlkBy] SysName NULL,

    [DBName] SysName NULL,

    [Command] SysName NULL,

    [CPUTime] int NULL,

    [DiskIO] int NULL,

    [LastBatch] SysName NULL,

    [ProgramName] SysName NULL,

    [SPID2] int NULL,

    [RequestId] int NULL)     

INSERT #Who2 exec sp_Who2

DELETE FROM #Who2

    WHERE Login = 'sa'

    OR HostName='.'

ALTER TABLE #Who2

        ADD LastDate DateTime

IF Month(@Now)=1 And Day(@Now)=1

BEGIN

    UPDATE #Who2

        SET LastDate=

            CASE WHEN LastBatch Like '12%'

                THEN Cast( Substring(LastBatch,1,5)+ '/'+ 

                            Cast(Year(@now)-1 As varchar(4)) +' '+ 

                            Substring(LastBatch,7,8) as DateTime)

            ELSE

                           Cast( Substring(LastBatch,1,5)+ '/'+ 

                           Cast(Year(@now) As varchar(4))+' ' + 

                          Substring(LastBatch,7,8) as DateTime)

            END    

END    

ELSE

BEGIN

    UPDATE #Who2

        SET LastDate=Cast( Substring(LastBatch,1,5)+ '/'+ 

                Cast(Year(@now) As varchar(4))+' ' + 

                Substring(LastBatch,7,8) as DateTime)

END

DECLARE Hit_List CURSOR FOR 

SELECT SPID FROM #Who2 Where Abs(DateDiff(mi,LastDate,@Now)) > 15

OPEN Hit_List

FETCH NEXT FROM Hit_List into @SpId

WHILE @@FETCH_STATUS=0

BEGIN

    SET @Cmd='KILL '+Cast(@SpId as nvarchar(11))

    EXEC(@Cmd)

    FETCH NEXT FROM Hit_List into @SpId

END

CLOSE Hit_List

DEALLOCATE Hit_List

DROP TABLE #Who2

GO

Password Policies

PCI DSS Requirements v3.22.2.4 Configure system security parameters to prevent misuse.

There are three required password policy settings...

All three settings are the default when creating users through SSMS.

Run the following T-SQL statement to find sysadmin or equivalent logins with CHECK_EXPIRATION = OFF. No rows should be returned...

SELECT l.[name], 'sysadmin membership' AS 'Access_Method' 

FROM sys.sql_logins AS l 

WHERE IS_SRVROLEMEMBER('sysadmin',name) = 1 

AND l.is_expiration_checked <> 1 

UNION ALL 

SELECT l.[name], 'CONTROL SERVER' AS 'Access_Method' 

FROM sys.sql_logins AS l 

JOIN sys.server_permissions AS p 

ON l.principal_id = p.grantee_principal_id 

WHERE p.type = 'CL' 

AND p.state IN ('G', 'W') 

AND l.is_expiration_checked <> 1;

Use the following code to determine the status of SQL Logins and if their password complexity is enforced...

SELECT name, is_disabled 

FROM sys.sql_logins 

WHERE is_policy_checked = 0;

For is_policy_checked... 0 = OFF, 1 = ONFor is_disabled... 1 = Disabled and unusable.

If no rows are returned then either no SQL Authenticated logins exist or they all have CHECK_POLICY ON.

Setting during manual user creation...

CREATE LOGIN WITH PASSWORD = '' MUST_CHANGE, CHECK_EXPIRATION = ON, CHECK_POLICY = ON;

Setting during manual password reset...

ALTER LOGIN WITH PASSWORD = '' MUST_CHANGE;

PCI DSS Requirements v3.2Requirement 8: Assign a unique ID to each person with computer access8.1 Define and implement policies and procedures to ensure proper user identification management for non-consumer users and administrators on all system components8.1.6 Limit repeated access attempts by locking out the user ID after not more than six attempts.8.1.7 Set the lockout duration to a minimum of 30 minutes or until an administrator enables the user ID.

Auditing & Logging

PCI DSS Requirements v3.22.2.4 Configure system security parameters to prevent misuse.

Maximum number of error log files

This setting controls the number of SQL Error Log Files that will be retained on disk.

Default is 6

The standard incremental daily TSM backup schedule should mean that these files are not lost but for PCI databases it is recommended to increase the setting to 12.or above.

Check

DECLARE @NumErrorLogs int; 

EXEC master.sys.xp_instance_regread 

N'HKEY_LOCAL_MACHINE', 

N'Software\Microsoft\MSSQLServer\MSSQLServer', 

N'NumErrorLogs', @NumErrorLogs OUTPUT; 

SELECT ISNULL(@NumErrorLogs, -1) AS [NumberOfLogFiles];

A return value of -1 indicates that the setting is NULL meaning the default setting of 6 is used.

This can also be checked (and changed) through SSMS.

Change

Change through SSMS , or...

EXEC master.sys.xp_instance_regwrite 

      N'HKEY_LOCAL_MACHINE', 

      N'Software\Microsoft\MSSQLServer\MSSQLServer', 

      N'NumErrorLogs', 

      REG_DWORD, 

      12;

Once the max number of error logs is reached, the oldest error log file is deleted each time SQL Server restarts or sp_cycle_errorlog is executed. 

Bibliography


https://msdn.microsoft.com/en-us/library/ms177285(v=sql.105).aspx - Configure SQL Server Error Logs (General Page)https://msdn.microsoft.com/en-us/library/ms177285(v=sql.100).aspx - Configure SQL Server Error Logs (General Page)

Default Trace Enabled

Check

SELECT name, 

      CAST(value as int) as value_configured, 

      CAST(value_in_use as int) as value_in_use 

FROM sys.configurations 

WHERE name = 'default trace enabled';

This option is enabled if both value columns show 1

Enable

In the event that this option is disabled, you can re-enable it using...

EXECUTE sp_configure 'show advanced options', 1; 

RECONFIGURE; 

EXECUTE sp_configure 'default trace enabled', 1; 

RECONFIGURE; 

GO 

EXECUTE sp_configure 'show advanced options', 0; 

RECONFIGURE;

See also

Extended Events

Bibliography


https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/default-trace-enabled-server-configuration-option

Login Auditing

Application Development

Encryption

Administrative Access

PCI DSS Requirements v3.22.3 Encrypt all non-console administrative access using strong cryptography. Note: Where SSL/early TLS is used, the requirements in Appendix A2 must be completed.

One potential mechanism for achieving this is by forcing SSL access via Citrix. Other options are available.

Additional Considerations

SQL Server Browser Service

Default Installation

In the case of a default instance installation, the SQL Server Browser service is disabled by default. Unless there is a named instance on the same server, there is no typically reason for the SQL Server Browser service to be running. In this case it is strongly suggested that the SQL Server Browser service remain disabled.

Named Instances

When it comes to named instances, given that a security scan can fingerprint a SQL Server listening on any port, it's therefore of limited benefit to disable the SQL Server Browser service. However, if all connections against the named instance are via applications and are not visible to end users, then configuring the named instance to listening on a static port, disabling the SQL Server Browser service, and configuring the apps to connect to the specified port should be the direction taken. This follows the general practice of reducing the surface area, especially for an unneeded feature. On the other hand, if end users are directly connecting to databases on the instance, then typically having them use ServerName\InstanceName is best. This requires the SQL Server Browser service to be running. Disabling the SQL Server Browser service would mean the end users would have to remember port numbers for the instances. When they don't that will generate service calls to IT staff. Given the limited benefit of disabling the service, the trade-off is probably not worth it, meaning it makes more business sense to leave the SQL Server Browser service enabled.


CIS_Microsoft_SQL_Server_2008_R2_Benchmark_v1.5.0

Bibliography

https://www.mssqltips.com/sqlservertip/3609/pci-best-practices-guide-for-sql-server-dbas/https://learn.cisecurity.org/benchmarkshttps://learn.microsoft.com/en-us/compliance/regulatory/offering-cis-benchmarkhttps://docs.microsoft.com/en-gb/archive/blogs/sql_server_isv/expiring-sessions-after-15-minutes-on-sql-server
https://docs.microsoft.com/en-us/sql/t-sql/statements/alter-login-transact-sql?view=sql-server-ver15https://docs.microsoft.com/en-us/sql/t-sql/statements/create-login-transact-sql?view=sql-server-ver15
https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms161959(v=sql.105)?redirectedfrom=MSDNhttps://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008/ms161959(v=sql.100)?redirectedfrom=MSDNhttps://www.sqlserver-dba.com/2016/03/how-to-check-sql-server-password-policy.html
https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/ad-hoc-distributed-queries-server-configuration-optionhttps://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-windows-service-accounts-and-permissions
https://msdn.microsoft.com/en-us/library/ms177285(v=sql.105).aspx - Configure SQL Server Error Logs (General Page)https://msdn.microsoft.com/en-us/library/ms177285(v=sql.100).aspx - Configure SQL Server Error Logs (General Page)
https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/default-trace-enabled-server-configuration-option
https://technet.microsoft.com/en-us/library/ms188470(v=sql.105).aspx - Server Properties (Security Page)https://technet.microsoft.com/en-us/library/ms188470(v=sql.100).aspx - Server Properties (Security Page)
http://www.sqlservercentral.com/articles/Security/sqlserverauditingpart1/1451/
https://www.brentozar.com/archive/2021/12/dont-use-sql-server-to-send-emails/
https://www.stigviewer.com/stig/ms_sql_server_2016_instance/2018-03-09/finding/V-79129
Microsoft Defender for SQLhttps://docs.microsoft.com/en-us/azure/defender-for-cloud/defender-for-sql-introductionhttps://azure.microsoft.com/en-gb/pricing/details/defender-for-cloud/