SQL получает ip-адрес хранимой процедуры вызова пользователя
Возможно ли, и если да, как получить удаленный IP-адрес пользователя, выполняющий запрос, аналогично, поскольку мы можем получить имя пользователя с помощью: SUSER_SNAME()
?
Обновление для баунти. Я ищу решение, которое позволяет захватить IP-адрес обычного смертного пользователя, а не владельца db. Идеи, предложенные TheGameiswar или njc, не позволяют зафиксировать IP-адрес пользователя, которому предоставлено только разрешение execute
. Однако они - отличные идеи, чтобы начать с проблемы. Здесь я перечисляю сущность идей:
Пожалуйста, смотрите следующую последовательность:
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/blahblah\admin_user, код ошибки 0x534.
Обновление после баунти. Bounty отправляется в Hadi для этой единственной строки кода, скрытой в их ответе:
CONNECTIONPROPERTY('client_net_address')
который позволяет захватывать IP-адрес любого смертного пользователя без предоставления каких-либо дополнительных прав пользователю или установки опции db TRUSTWORTHY ON и даже создания процедуры WITH EXECUTE AS OWNER
. Браво! Спасибо всем за участие.
Ответы
Ответ 1
Общая информация
Есть два способа получить текущую информацию о подключении
1. Получение информации из Динамические представления Managemenet
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
END
3. если вы хотите предоставить пользователю (пользователю базы данных) выполнение хранимой процедуры, вы должны использовать эту команду
GRANT EXECUTE ON MyStoredProcedure TO User;
Существует много подробных статей и ответов о проблеме, с которой вы столкнулись, и многие предлагаемые решения, такие как установка базы данных в режиме TRUSTWORTHY
(перед ее использованием прочитайте первую ссылку ниже) и доверяйте аутентификатору и другим методы. Вы можете найти их в ссылках ниже
Примечание. Вы можете проверить ответ @SteveFord для использования свойства TRUSTWORTHY
4.Если вы хотите заблокировать подключения, за исключением определенных IP-адресов, вы должны следовать этому ответу
Также существует множество сценариев, которые можно использовать для получения IP-адресов клиента или сервера, которые можно найти в следующем вопросе:
Ссылки
Ответ 2
Вы можете использовать соединения 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 для client_net_address
Адрес хоста клиента, подключающегося к этому серверу. Недействителен.
Ответ 3
Использование оператора EXECUTE AS OWNER
в CREATE PROCEDURE
Заявление:
От 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
Чтобы получить IP-адрес вызывающего абонента и имя пользователя без предоставления всех специальных разрешений, вы можете немного обмануть сервер и базу данных. Для этого необходимо несколько вещей:
-
ALTER DATABASE MyDataBase SET TRUSTWORTHY ON
- Создайте логин (не
[user_mortal_jack]
) в моем примере [user_immortan_joe]
- Создайте пользователя для
[user_immortan_joe]
в MyDataBase
- В контексте
master
grant VIEW SERVER STATE to [user_immortan_joe];
- В
MyDataBase
создайте хранимую процедуру (не MyStoredProcedure
, в моем примере get_ip
), которая получает int, представляющий конкретный параметр session_id
, будет output
(выводить, а не возвращать) IP-адрес от этого session_id
. Создайте его with execute as 'user_immortan_joe'
- Создайте MyStoredProcedure таким образом, чтобы с помощью
get_ip
и SUSER_SNAME()
возвращался IP-адрес и имя пользователя вызывающего.
Таким образом вы получаете IP и имя пользователя любого вызывающего абонента MyStoredProcedure
в соответствии с принципом наименьшей привилегии и избегаете проблем, с которыми вы столкнулись при решении.
Пример 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