web-dev-qa-db-ja.com

ストアドプロシージャ(SQL)を呼び出すときにユーザーのIPアドレスを取得する

同様に、クエリを実行してユーザーのリモートIPアドレスを取得することは可能で、その方法は次のとおりです。SUSER_SNAME()

バウンティの前に更新

データベース所有者ではなく、一般の一般ユーザーのIPアドレスを取得できるソリューションを探しています。 TheGameiswarまたはnjcによって提案されたアイデアでは、execute権限のみが付与されているユーザーのIPアドレスを取得することはできません。しかし、それらは問題から始めるための優れたアイデアです。ここに私はアイデアの本質をリストします:

私が従うシーケンスを見てください:

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

次に、ユーザーを追加して権限を付与します。

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

GRANT EXECUTE ON MyStoredProcedure TO [user_mortal_jack];

クエリでプロシージャを実行すると:

EXECUTE AS USER = 'user_mortal_jack'
exec MyStoredProcedure
REVERT

エラーメッセージが表示されます。

実行中のモジュールは信頼されていません。モジュールのデータベースの所有者に認証権限を付与するか、モジュールにデジタル署名する必要があります。

追加の許可を与えても、このメッセージが表示されます。

grant VIEW SERVER STATE to [user_mortal_jack];

ストアドプロシージャの先頭を次のように変更した場合:

create procedure MyStoredProcedure
with execute as OWNER as 

私はさまざまな種類のエラーに終わります:

Windows NTグループ/ユーザー 'blahblah\admin_user'に関する情報を取得できませんでした。エラーコード0x534。

バウンティ後に更新

賞金は、回答に隠された次の1行のコードに対してハディに付与されます。

CONNECTIONPROPERTY('client_net_address')

これにより、ユーザーに追加の権限を付与したり、データベースのTRUSTWORTHY ONオプションを設定したり、プロシージャを作成したりすることなく、一般ユーザーのIPアドレスを取得できますWITH EXECUTE AS OWNER句。

17

一般的な情報

現在の接続情報を取得するには2つの方法があります

  1. 動的管理ビューから情報を取得

    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. [〜#〜] connectionproperty [〜#〜] 関数の使用(SQL Server 2008以降のバージョン):

    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
    

推奨されるソリューション

  1. ユーザーに特定のIPアドレスを付与する場合

    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. 許可されたIPアドレスを含むテーブルがあると仮定します(つまり、TBL_IP

    CREATE PROCEDURE MyStoredProcedure AS BEGIN 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
    

    終わり

  3. ストアドプロシージャを実行するユーザー(データベースユーザー)を許可する場合は、このコマンドを使用する必要があります

    MyStoredProcedureの実行をユーザーに許可します。

    あなたが直面している問題について話している多くの詳細な記事と回答、そしてTRUSTWORTHYモードでのデータベースの設定(使用する前に以下の最初のリンクを読んでください)やオーセンティケーターの信頼、およびその他の方法。あなたは以下のリンクでそれらを見つけることができます

    注:TRUSTWORTHY property を使用して@SteveFordの回答を確認できます

  4. 特定のIPアドレス以外の接続をブロックする場合は、この回答に従う必要があります

    また、以下の質問で見つけることができるクライアントまたはサーバーのIPアドレスを取得するために使用できる多くのスクリプトがあります:

参照

14
Hadi

EXECUTE AS OWNERステートメントでCREATE PROCEDUREステートメントを使用する:

From[〜#〜] msdn [〜#〜]

CALLER以外のコンテキストで実行するように指定されたモジュールをユーザーが実行すると、モジュールを実行するユーザーの権限がチェックされますが、モジュールによってアクセスされるオブジェクトに対する追加の権限チェックは、 EXECUTE AS句。モジュールを実行しているユーザーは、事実上、指定されたユーザーになりすましています。

モジュールのEXECUTE AS句で指定されたコンテキストは、モジュールの実行中のみ有効です。モジュールの実行が完了すると、コンテキストは呼び出し元に戻ります。

以下は、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

次に、ストアドプロシージャを実行するためのアクセス許可をユーザーに与える必要があります。

適切な権限を作成するための更新

データベースを信頼できるように設定する必要があります( データベースを信頼できるように設定する を参照):

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];

私はこれをテストしましたが、これは期待通りに機能します

4
Steve Ford

接続DMVを使用してそれを実現できます。

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 for client_net_address

このサーバーに接続しているクライアントのホストアドレス。 null可能です。

4
TheGameiswar

呼び出し元のIPアドレスとユーザー名のすべてに特別な権限を付与せずに取得するには、cheatサーバーとデータベースを少し変更します。これを実現するには、いくつかのことが必要です。

  1. _ALTER DATABASE MyDataBase SET TRUSTWORTHY ON_
  2. 私の例ではログインを作成します(_[user_mortal_jack]_ではありません)_[user_immortan_joe]_
  3. MyDataBaseに_[user_immortan_joe]_のユーザーを作成する
  4. master _grant VIEW SERVER STATE to [user_immortan_joe];_のコンテキストで
  5. MyDataBaseで、特定の_get_ip_パラメータを表すintを受け取っているストアドプロシージャ(MyStoredProcedureではなく、例では_session_id_)を作成しますoutput(出力ではなく)IPアドレスまたはその_session_id_。それを_with execute as 'user_immortan_joe'_で作成します。
  6. MyStoredProcedureは、_get_ip_およびSUSER_SNAME()を使用して、呼び出し元のIPアドレスとユーザー名を返すように作成します。

このようにして、最小限の特権の原則を尊重し、解決策の追求中に遭遇した問題を回避するMyStoredProcedureの呼び出し元のIPアドレスとユーザー名を取得します。

サンプルスクリプト:

_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
_