Je souhaite restreindre les connexions à mon instance SQL Server à des adresses IP spécifiques. Je souhaite empêcher toute connexion à partir d'une adresse IP, à l'exception d'une liste spécifique. Est-ce quelque chose qui peut être configuré dans l'instance ou la base de données SQL Server?
Cela ressemble à quelque chose que vous feriez en utilisant le Pare-feu Windows (vous pouvez bloquer les ports SQL Server et autoriser des exceptions pour certaines adresses IP).
Vous pouvez le faire avec quelque chose comme un déclencheur de connexion qui vérifie l'adresse IP à l'aide de sys.dm_exec_connections mais je pense que c'est une option beaucoup moins souhaitable que de bloquer le trafic.
Certainement beaucoup plus difficile à faire au niveau de la base de données.
J'ai écrit cette fonctionnalité pour interdire automatiquement une adresse IP qui a fait plus de X ( @ FailedLoginAttempts ) tentatives de connexion à partir de la même adresse IP. Il est basé sur les journaux d'erreurs SQL Server. J'utilise Windows Server 2008 et SQL Server 2008 R2.
Sachez que si vous n'avez pas parcouru vos journaux d'erreurs SQL Server depuis un certain temps, vous pouvez obtenir un grand nombre d'adresses IP et cela peut prendre un peu de temps pour tout traiter. Comme je l'exécute toutes les 10 minutes, l'ensemble du processus prend environ 4 à 5 secondes.
Créer la table pour stocker les adresses IP interdites
/* Create table to store banned IP addresses */
USE [YourDB]
GO
CREATE TABLE [dbo].[autobanned_ipaddesses](
[id] [int] IDENTITY(1,1) NOT NULL,
[ipaddress] [varchar](50) NOT NULL,
[attacked_on] [datetime2](2) NOT NULL,
[banned_on] [datetime2](7) NOT NULL,
[number_login_attempts] [int] NULL,
CONSTRAINT [PK_autobanned_ipaddesses] PRIMARY KEY CLUSTERED
([id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]) ON [PRIMARY]
ALTER TABLE [dbo].[autobanned_ipaddesses] ADD CONSTRAINT [DF_autobanned_ipaddesses_banned_on] DEFAULT (getdate()) FOR [banned_on]
Créez le processus pour ajouter automatiquement des adresses IP au pare-feu. Personnellement, j'ai placé ce code dans un travail d'agent exécuté toutes les 10 minutes. Notez également que ce processus utilise xp_cmdshell . Je ne veux certainement pas débattre des avantages d'activer ou de désactiver cette fonctionnalité. À chacun, mais mon script ne fonctionnera pas sans cette fonctionnalité. Si vous ne l'avez pas activé ici est un bon lien pour vous aider.
USE [YourDB]
DECLARE @T TABLE(LogDate datetime,ProcessInfo varchar(200),Text varchar(max))
DECLARE @T2 TABLE(LogDate datetime,ProcessInfo varchar(200),IPAddress varchar(max))
DECLARE @T3 TABLE(LogDate datetime,IPAddress varchar(max))
DECLARE @IPAddress varchar(50),@LogDate datetime,@NumLoginAttempts int,@CmdExc varchar(300),@FailedLoginAttempts int=10
BEGIN /* Get error log records with failed login attempt data */
INSERT INTO @T
EXEC sp_readerrorlog 0,1,'Could not find a login matching the name provided'
INSERT INTO @T
EXEC sp_readerrorlog 0,1,'An error occurred while evaluating the password'
END
BEGIN /* Get the IP address from T*/
INSERT INTO @T2
SELECT LogDate,ProcessInfo,REPLACE(REPLACE( SUBSTRING(Text, PATINDEX ('%[0-9].%[0-9].%[0-9].[0-9]%',Text)-2,50),']',''),':','') FROM @T
END
BEGIN /* Get the NEW ip addresses from T2*/
INSERT INTO @T3
SELECT CONVERT(varchar(10),LogDate,101) LogDate,IPAddress from @T2 T
WHERE NOT EXISTS(SELECT * FROM autobanned_ipaddesses ai WHERE ai.ipaddress=T.IPAddress)
GROUP BY CONVERT(varchar(10),LogDate,101),IPAddress
HAVING COUNT(LogDate)>@FailedLoginAttempts
ORDER BY IPAddress
END
BEGIN /* Validate that T3 has records, if not skip the firewall add */
IF (SELECT COUNT(*) FROM @T3)=0
BEGIN
GOTO ExitWithoutCycle
END
END
BEGIN /* Loop through T3 and add each entry to the windows firewall */
WHILE EXISTS(SELECT * FROM @T3)
BEGIN
SELECT TOP(1) @LogDate=LogDate, @IPAddress=IPAddress FROM @T3
SELECT @NumLoginAttempts=COUNT(*) FROM @T2 WHERE IPAddress=@IPAddress
INSERT INTO autobanned_ipaddesses (attacked_on,ipaddress,number_login_attempts) VALUES(@LogDate,@IPAddress,@NumLoginAttempts)
SET @CmdExc = 'netsh advfirewall firewall add rule name="Autobanned IP - SQL Attacked '+@IPAddress+'" dir=in action=block enable="yes" remoteip='+@IPAddress+' protocol=any interfacetype=any'
EXEC master..xp_cmdshell @CmdExc
DELETE @T3 WHERE IPAddress=@IPAddress
END
END
/* sp_cycle_errorlog archives the current error log. */
EXEC sp_cycle_errorlog
ExitWithoutCycle:
Je comprends que ce n'est pas une solution parfaite, car cela ne fonctionne qu'avec les adresses IP IPv4 et ne regarde que les tentatives de connexion effectuées via probablement le port 1433 en fonction de votre configuration. Cependant, cela m'a aidé à identifier et à bloquer plus de 100 adresses IP en une semaine (principalement en Chine et à Hong Kong, mais j'ai bloqué le Department of Homeland Security).
[~ # ~] tangente [~ # ~] - Une fois que j'ai exécuté cela pendant une semaine, j'ai rapidement réalisé qu'il y avait une bonne quantité de modèles dans les plages nettes des adresses IP. J'ai trouvé cet outil pour être le plus utile pour déterminer qui et d'où venaient ces hits. Ce qui est génial avec ce site Web, c'est qu'une fois que vous obtenez l'emplacement de l'adresse IP, en dessous, vous pouvez saisir à nouveau l'adresse IP et obtenir la plage nette de l'adresse IP. Par exemple (désolé la Chine), j'ai trouvé que 59.53.67.13 avait une plage nette de 59.0.0.0 - 59.255.255.255. Cela étant dit, j'ai créé une fonction manuelle pour bloquer toute la plage nette et supprimer toutes les règles du pare-feu Windows qui contenaient déjà des adresses IP dans cette plage.
USE [YourDB]
DECLARE @CmdExc varchar(300)
DECLARE @NetRange varchar(50)='59.0.0.0 - 59.255.255.255'
DECLARE @NetRangeFrom varchar(20),@NetRangeTo varchar(20),@IPAddress varchar(20)
DECLARE @IPPart2From int,@IPPart2To int
DECLARE @IPPartSearch2From int,@IPPartSearch2To int
DECLARE @T Table (ipaddress varchar(20))
SET @NetRange=REPLACE(@NetRange,' ','')
SELECT @NetRangeFrom=LTRIM(RTRIM(SUBSTRING(@NetRange,1,CHARINDEX('-',@NetRange)-1)))
SELECT @NetRangeTO=LTRIM(RTRIM(SUBSTRING(@NetRange,CHARINDEX('-',@NetRange)+1,50)))
SELECT @IPPartSearch2From=CAST(PARSENAME(@NetRangeFrom,3) as int)
SELECT @IPPartSearch2To=CAST(PARSENAME(@NetRangeTo,3) as int)
INSERT INTO @T
select ai.ipaddress from autobanned_ipaddesses ai where LTRIM(ai.ipaddress) like SUBSTRING(@NetRangeFrom,1,CHARINDEX('.',@NetRangeFrom,1))+'%' AND PARSENAME(LTRIM(RTRIM(ai.ipaddress)),3) BETWEEN @IPPartSearch2From AND @IPPartSearch2To
SET @CmdExc = 'netsh advfirewall firewall add rule name="AB SQL Attacked '+@NetRange+'" dir=in action=block enable="yes" remoteip='+@NetRange
EXEC master..xp_cmdshell @CmdExc
WHILE EXISTS(SELECT * from @T)
BEGIN
SELECT TOP(1) @IPAddress=ipaddress from @T
SET @CmdExc = 'netsh advfirewall firewall delete rule name="Autobanned IP - SQL Attacked '+@IPAddress+'"'
EXEC master..xp_cmdshell @CmdExc
DELETE TOP(1) FROM @T
END
J'ai hâte de recevoir des commentaires qui amélioreront cette fonctionnalité.
Je suppose que vous pourriez écrire un déclencheur d'ouverture de session comme décrit ici qui vérifie d'où ils se connectent, mais je suggère qu'il serait préférable d'utiliser un pare-feu.