MSSQL Security
The following section provides guidance for security hardening MS-SQL Database Instances. It highlights how the recommendations tie-in with PCI compliance.
TODO:
Contained Databases
Row-Level Security
Dynamic Data Masking
Extensible Key Management (EKM)
Microsoft Defender for SQL
Patching & Upgrades
Single Function Servers
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
Ad Hoc Distributed Queries
Default: Disabled
Target: Disabled
Enabling Ad Hoc Distributed Queries allows users to query data and execute statements on external data sources.
This is Disabled by default. Enable only if 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 = '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)
Default: Disabled
Target: Disabled
Cross DB Ownership Chaining
Default: Disabled
Target: Disabled
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
Database Mail XPs
Default: Disabled
Target: Disabled
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
Default: Disabled
Target: Disabled
Enabling SQL Mail XPs provides a mechanism to send, receive, delete and process email messages using SQL Server
This is Disabled by default. Enable only if fully justified.
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
Default: Disabled
Target: Disabled
Enabling Ole Automation Procedures enables the ability to instantiate OLE Automation objects within T-SQL batches.
These are extended stored procedures that allow SQL Server users to execute functions external to SQL Server.
This is Disabled by default. Enable only if 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 = '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
Default: Enabled
Target: DISABLED
Enabling Remote Access enables the execution of local stored procedures on remote servers or remote stored procedures on local server.
This is Enabled by default. Enable only if fully justified.
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
Default: Disabled
Target: Disabled
Scan For Startup Procs
Default: Disabled
Target: Disabled
Enabling 'Scan For Startup Procs' causes SQL Server to scan for and automatically run all stored procedures that are set to execute upon service startup.
This is Disabled by default. Enable only if fully justified.
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
Default: OFF; except for MSDB database where it MUST be ON
Target: OFF; except MSDB
The TRUSTWORTHY database property is used to indicate whether the instance of SQL Server trusts the database and the contents within it.
This property could allow database objects to access objects in other databases under certain circumstances.
It is OFF (0) by default (except for MSDB database where it MUST be ON). Set it to ON only if fully justified.
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
Default: TCP/IP and Shared Memory protocols are enabled
Target: Disable Unnecessary SQL Server Protocols
All network protocols are installed by SQL Server Setup, but may or may not be enabled.
Use SQL Server Configuration Manager to enable or disable network protocols.
The Database Engine must be stopped and restarted for the change to take effect.
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
Default: NO
Target: YES (But, this is only necessary for non-clustered production instances)
Designating an instance as hidden prevents advertisement by the SQL Server Browser service.
Instances are not hidden by default.
Hiding an instance does not prevent users from connecting to server if they know the instance name and port.
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
Default: 'sa' is 'sa'
Target: Rename 'sa' login account / Disable 'sa' Login Account
xp_cmdshell
Default: Disabled
Target: Disabled
Enabling 'xp_cmdshell' allows the xp_cmdshell extended stored procedure to be used by an authenticated SQL Server user to execute operating-system command shell commands and return results as rows within the SQL client
This is Disabled by default. Enable only if 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 = '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
Non-Standard Ports
Default: 1433
Target: Consider changing
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.
For extra security it is recommended (by the CIS benchmark) to run SQL Server on a non-standard port (i.e. a port other than 1433).
Changing the port requires an instance restart. It will also require a client change (creation of an alias or changing code to use a custom connect string).
Ideally this should be discussed and documented at service design time.
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
Server Authentication
Default: Windows Authentication Mode, but this is likely to have been changed
Target: Windows Authentication Mode
There are two types of Server Authentication...
Windows Authentication Mode
Mixed Mode - A combination of Windows Authentication Mode and SQL Server Authentication Mode
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 ModeSet
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
Default: GUEST is NOT granted CONNECT permission
Target: GUEST is NOT granted CONNECT permission
CONNECT Privileges should be REVOKED from GUEST for all databases except for MASTER, MSDB and TEMPDB to ensure that a login is not able to access database information without explicit access to do so.
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-databasesOrphaned Users
Regular Check Required
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).aspxUser - MSSQL Service Account
Check the SQL Server’s MSSQL Service Account is Not an Administrator
The MSSQL Service Account name should own the MS-SQL Services
The service account (in case of a local or AD account) and service SID should not be members of the Windows Administrators group.
Check
Start "Computer Management" (compmgmt.msc)
Select "Local Users and Groups"
Select "Groups"
Double-click the "Administrators" group
The MSSQL Service Account name should not appear in the list of members...
User - SQLAgent Service Account
Check the SQL Server’s SQLAgent Service Account is Not an Administrator
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..
Start "Computer Management" (compmgmt.msc)
Select "Local Users and Groups"
Select "Groups"
Double-click the "Administrators" group
The MSSQL Service Account name should not appear in the list of members...
Service Account - Full-Text
Default: the Service Account (or Service SID) is not a member of the Administrators group
Target: Ensure the SQL Server’s Full-Text Service Account is Not an Administrator
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
Default: no non-default permissions are granted to the public server role
Default: the msdb public database role does not have access to any proxy
Target: Ensure only the default permissions specified by Microsoft are granted to the public server role
Target: Ensure the public role in the msdb database is not granted access to SQL Agent proxies
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
SQL Logins
Default: no BUILTIN groups are added as SQL logins
Default: no Windows local groups are added as SQL logins
Target: Ensure Windows BUILTIN groups are not SQL Logins
Target: Ensure Windows local groups are not 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...
Create an equivalent AD group containing only the required user accounts (if needed).
Add the AD group or individual Windows accounts as a SQL Server LOgin and grant permissions as required.
Drop the BUILTIN login...
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...
Create an equivalent AD group containing only the required user accounts (if needed).
Add the AD group or individual Windows accounts as a SQL Server LOgin and grant permissions as required.
Drop the local Windows group login...
USE [master]
GO
DROP LOGIN [<name>]
GO
Expiring Sessions
Default: Sessions do not expire
Target: Expire 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-serverCreate 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
Default: MUST_CHANGE Option is set to 'ON' for All SQL Authenticated Logins when using SSMS to create a SQL authenticated login; OFF when using T-SQL CREATE LOGIN syntax
Default: CHECK_EXPIRATION Option is set to 'ON' for All SQL Authenticated Logins Within the Sysadmin Role when using SSMS to create a SQL authenticated login; but OFF when using T-SQL CREATE LOGIN syntax
Default: CHECK_POLICY Option is set to 'ON' for All SQL Authenticated Logins
Target: MUST_CHANGE' Option is set to 'ON' for All SQL Authenticated Logins
Target: CHECK_EXPIRATION' Option is set to 'ON' for All SQL Authenticated Logins Within the Sysadmin Role
Target: CHECK_POLICY Option is set to 'ON' for All SQL Authenticated Logins
There are three required password policy settings...
MUST_CHANGE
CHECK_EXPIRATION
CHECK_POLICY
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;
To check the password policy in force, use secpol.msc (Local Security Policy). The policies are set at domain level.
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
Auditing & Logging
Maximum number of error log files
Default: 6
Target: 12+
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
Default: 1 (ON)
Target: 1 (ON)
The default trace provides audit logging of database activity including account creations, privilege elevation and execution of DBCC commands.
Default is 1 (ON)
Do not disable this setting without full justification.
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 1Enable
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
Default: Audit Failed Logins
Target: Audit Failed and Successful logins
Application Development
Encryption
Target: Ensure 'Symmetric Key encryption algorithm' is set to 'AES_128' or higher in non-system databases
Target: Ensure Asymmetric Key Size is set to 'greater than or equal to 2048' in non-system databases
Administrative Access
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/
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/