web-dev-qa-db-fra.com

Obtenir l'adresse IP d'un utilisateur en appelant une procédure stockée (SQL)

Est-il possible, et si oui comment, d'obtenir que l'adresse IP distante d'un utilisateur exécute la requête, de la même manière que nous pouvons obtenir le nom de l'utilisateur avec: SUSER_SNAME()?

Mise à jour avant prime

Je cherche une solution qui permette de récupérer l'adresse IP d'un utilisateur mortel ordinaire, pas d'un propriétaire de base de données. Les idées proposées par TheGameiswar ou njc ne permettent pas de capturer l’adresse IP d’un utilisateur à qui une autorisation execute a été accordée. Cependant, ce sont d'excellentes idées pour commencer avec le problème. Ici, je liste l'essentiel des idées:

S'il vous plaît voir la séquence que je suis:

create procedure MyStoredProcedure as
select client_net_address 
from sys.dm_exec_connections
where session_id = @@SPID

Maintenant, ajoutez un utilisateur et accordez la permission:

CREATE LOGIN [user_mortal_jack] WITH PASSWORD=N'LongYouLive!!!';

GRANT EXECUTE ON MyStoredProcedure TO [user_mortal_jack];

Lorsque j'exécute la procédure avec une requête:

EXECUTE AS USER = 'user_mortal_jack'
exec MyStoredProcedure
REVERT

Je reçois un message d'erreur:

Le module en cours d'exécution n'est pas approuvé. Soit le propriétaire de la base de données du module doit être autorisé à s'authentifier, soit le module doit être signé numériquement.

Je recevrai ce message même si j'accorde une permission supplémentaire:

grant VIEW SERVER STATE to [user_mortal_jack];

Si je change le début de la procédure stockée en:

create procedure MyStoredProcedure
with execute as OWNER as 

Je me retrouve avec une sorte d'erreur différente:

Impossible d'obtenir des informations sur le groupe/utilisateur Windows NT 'blahblah\admin_user', code d'erreur 0x534.

Mise à jour après la prime

La prime est accordée à Hadi pour cette seule ligne de code cachée dans sa réponse:

CONNECTIONPROPERTY('client_net_address')

qui capturons l’adresse IP de tout utilisateur mortel sans accorder aucun droit supplémentaire à l’utilisateur ni définir l’option TRUSTWORTHY ON de la base de données, ni même créer une clause de procédure WITH EXECUTE AS OWNER.

17
Przemyslaw Remin

Informations générales

Il existe deux manières d'obtenir les informations de connexion actuelles.

  1. Obtention d'informations à partir de Vues de gestion dynamiques

    SELECT
    conn.session_ID as SPID,
    conn.client_net_address as IPAddress,
    sess.Host_name as MachineName,
    sess.program_name as ApplicationName,
    login_name as LoginName
    FROM sys.dm_exec_connections conn
    inner join sys.dm_exec_sessions sess
    on conn.session_ID=sess.session_ID
    
  2. Utilisation de CONNECTIONPROPERTY function (SQL Server 2008 et version ultérieure):

    select
    CONNECTIONPROPERTY('net_transport') AS net_transport,
    CONNECTIONPROPERTY('protocol_type') AS protocol_type,
    CONNECTIONPROPERTY('auth_scheme') AS auth_scheme,
    CONNECTIONPROPERTY('local_net_address') AS local_net_address,
    CONNECTIONPROPERTY('local_tcp_port') AS local_tcp_port,
    CONNECTIONPROPERTY('client_net_address') AS client_net_address
    

Solutions suggérées

  1. Si vous souhaitez donner à l'utilisateur une adresse IP spécifique

    CREATE PROCEDURE MyStoredProcedure AS
    BEGIN
        DECLARE @IP_Address varchar(255);
    
        SELECT @IP_Address = CAST(CONNECTIONPROPERTY('client_net_address') as varchar(200))
    
        IF @IP_Address = 'XXX.XXX.XXX.XXX'
        SELECT TOP 1 FROM tb
    
    END
    
  2. En supposant que vous ayez une table contenant l'adresse IP attribuée (c'est-à-dire TBL_IP)

    CREATE PROCEDURE MyStoredProcedure AS COMMENCE DECLARE @IP_Address varchar (255);

    SELECT @IP_Address = CAST(CONNECTIONPROPERTY('client_net_address') as varchar(200))
    
    IF EXISTS (SELECT 1 FROM TBL_IP WHERE [IP] = @IP_Address )
    SELECT TOP 1 FROM tb
    

    FIN

  3. Si vous souhaitez autoriser un utilisateur (utilisateur de base de données) à exécuter une procédure stockée, vous devez utiliser cette commande

    GRANT EXECUTE ON MyStoredProcedure TO User;

    Il existe de nombreux articles détaillés et réponses concernant le problème auquel vous êtes confronté, ainsi que de nombreuses solutions suggérées, telles que la définition de la base de données en mode TRUSTWORTHY (avant de l'utiliser, lisez le premier lien ci-dessous), la confiance en l'authentificateur et d'autres méthodes. Vous pouvez les trouver dans les liens ci-dessous

    _ {Remarque: vous pouvez vérifier la réponse de @SteveFord pour utiliser la propriété TRUSTWORTHY} _

  4. Si vous souhaitez bloquer des connexions, à l'exception d'adresses IP spécifiques, vous devez suivre cette réponse.

    De nombreux scripts peuvent également être utilisés pour obtenir des adresses IP de clients ou de serveurs, comme indiqué ci-dessous:}

Références

14
Hadi

Utilisation de l'instruction EXECUTE AS OWNER dans une instruction CREATE PROCEDURE:

DeMSDN

Lorsqu'un utilisateur exécute un module qui a été spécifié pour s'exécuter dans un fichier contexte autre que CALLER, autorisation de l'utilisateur à exécuter le module est cochée, mais des autorisations supplémentaires vérifient les objets qui sont accessibles par le module sont exécutés sur le compte utilisateur spécifié dans la clause EXECUTE AS. L'utilisateur exécutant le module est, en effet, usurper l'identité de l'utilisateur spécifié. 

Le contexte spécifié dans la clause EXECUTE AS du module est valide seulement pour la durée de l'exécution du module. Le contexte revient au appelant lorsque l'exécution du module est terminée.

Les éléments suivants doivent être créés par un utilisateur disposant des autorisations nécessaires pour interroger les DMV.

CREATE PROCEDURE MyStoredProcedure
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON
   SELECT TOP 1
   FROM tb
   INNER JOIN sys.dm_exec_connections cn
         ON tb.client_net_address = cn.client_net_address
   WHERE cn.Session_Id = @@SPID
END

Ensuite, vous devrez donner aux utilisateurs les autorisations nécessaires pour exécuter la procédure stockée:

Mettre à jour pour créer les autorisations adéquates

Vous devrez définir votre base de données sur Trustworthy (voir Définir la base de données sur Trustworthy :

ALTER DATABASE MyDataBase SET TRUSTWORTHY ON

CREATE LOGIN [user_mortal_jack] WITH PASSWORD=N'LongYouLive!!!';

CREATE USER [user_mortal_jack] FOR LOGIN [user_mortal_jack] WITH DEFAULT_SCHEMA=[dbo]
GO

GRANT EXECUTE ON MyStoredProcedure TO [user_mortal_jack];

J'ai testé cela et cela fonctionne maintenant comme prévu

4
Steve Ford

Vous pouvez utiliser les connexions DMV pour y parvenir.

select ec.client_net_address,* from sys.dm_exec_connections ec
join
sys.dm_exec_requests rq
on rq.connection_id=ec.connection_id
cross apply
sys.dm_exec_sql_text(rq.sql_handle) txt
where txt.text like '%your stored proc%'

MSDN pour client_net_address

Adresse d'hôte du client se connectant à ce serveur. Est nullable.

4
TheGameiswar

Pour obtenir l'adresse IP et le nom d'utilisateur d'un appelant sans lui accorder des autorisations spéciales, vous pouvez tricher le serveur et la base de données un peu. Deux choses sont nécessaires pour y parvenir:

  1. ALTER DATABASE MyDataBase SET TRUSTWORTHY ON
  2. Créer un identifiant (pas [user_mortal_jack]) dans mon exemple [user_immortan_joe]
  3. Créez un utilisateur pour [user_immortan_joe] dans MyDataBase
  4. Dans le contexte de mastergrant VIEW SERVER STATE to [user_immortan_joe];
  5. Dans MyDataBase, créez une procédure stockée (et non pas MyStoredProcedure, dans mon exemple get_ip) qui reçoit un int représentant un paramètre session_id spécifique output (sortie, pas retour) l'adresse IP ou session_id. Créez-le with execute as 'user_immortan_joe'.
  6. Créez MyStoredProcedure de manière à ce que, avec l'aide de get_ip et de SUSER_SNAME(), l'adresse IP et le nom d'utilisateur de l'appelant soient renvoyés.

De cette façon, vous obtenez l'adresse IP et le nom d'utilisateur de tout appelant de MyStoredProcedure en respectant le principe du moindre privilège et en évitant les problèmes que vous avez rencontrés lors de la recherche d'une solution.

Exemple de script:

use MyDataBase
go
alter database MyDataBase set  trustworthy on;
go

CREATE LOGIN [user_mortal_jack] WITH PASSWORD=N'LongYouLive!!!';
go
create user [user_mortal_jack];
go

CREATE LOGIN [user_immortan_joe] WITH PASSWORD=N'ToTheGatesOfValhalla!!!';
go
create user [user_immortan_joe];
go

use master
go
grant VIEW SERVER STATE to [user_immortan_joe];

use MyDataBase
go


create  PROCEDURE get_ip
@spid int, @ip varchar(50) output
with execute as 'user_immortan_joe'
as
begin
    select @ip = client_net_address
    from sys.dm_exec_connections
    where session_id =  @spid
end;
go

create procedure MyStoredProcedure
as
begin
    declare @spid int = @@spid, @ip varchar(50);
    exec dbo.get_ip @spid,@ip output;
    select @ip as ipAddress ,SUSER_SNAME() as userName
end
go

GRANT EXECUTE ON MyStoredProcedure TO [user_mortal_jack];
go

EXECUTE AS USER = 'user_mortal_jack'
exec MyStoredProcedure
REVERT
1