从我的数据库授予用户执行 xp_cmdshell

Van*_*nel 2 sql-server permissions

我正在使用 SQL Server 2016,我需要让用户MyDatabase执行xp_cmdshell. 我执行以下操作:

USE [MyDatabase]
GO

GRANT EXECUTE ON xp_cmdshell TO myUser
GO
Run Code Online (Sandbox Code Playgroud)

myUser是一个用户MyDatabase,当我运行上面的代码时,登录为sa,我收到以下错误:

只有当当前数据库是 master 时,才能授予对服务器范围目录视图或系统存储过程或扩展存储过程的权限。

我需要将用户添加到master数据库吗?我不认为这是安全的。

我需要这个,因为我想从存储过程中编写一个文本文件。我找到了以下文章http://www.nigelrivett.net/WriteTextFile.html,说我可以使用以下方法编写文本文件:

You will need to create the data to be output as in dynamic sql statements
The first command here creates or overwrites the file - the rest append to the file.
exec master..xp_cmdshell 'echo hello > c:\file.txt'
exec master..xp_cmdshell 'echo appended data >> c:\file.txt'
exec master..xp_cmdshell 'echo more data >> c:\file.txt'
Run Code Online (Sandbox Code Playgroud)

我问这个是因为我的存储过程将生成一个大字符串 (nvarchar(max)) json,当我尝试用 C# 写下它时,我什么也没得到:文件或异常都没有。我想在存储过程中写入 json 字符串(如果可以的话)。

存储过程正确结束,我已经检查了调试器,我在输出参数 json 中得到了一些东西(我知道这是因为 Visual Studio 设置没有足够的内存来显示其内容),File.WriteAllText因为我有一个断点而运行它,而且,路径是绝对的。但也许,有些东西我忽略了,我必须再次仔细检查所有内容。

Dan*_*man 5

我建议您将执行 xp_cmdshell 的代码包装在用户数据库中的存储过程中,并使用具有所需权限的证书对其进行签名。这样,用户就被限制在用户存储过程中,并且不能执行 ad-hoc xp_cmdshell 命令。操作系统权限也仅限于非系统管理员角色成员的代理帐户。Erland Sommarskog 的“存储过程中的打包权限”一文详细介绍了此证书技术。

下面是一个示例脚本。

-- Enable xp_cmdshell and create proxy account
USE master;
EXEC sp_configure 'show',1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell',1;
RECONFIGURE; 
EXEC dbo.sp_xp_cmdshell_proxy_account 'YourDomain\YourProxyAccount', 'YourPr0xy@accountPassw0rd';
GO

-- Create certificate in master.
CREATE CERTIFICATE xp_cmdshell_cert
   ENCRYPTION BY PASSWORD = 'All you need is love'
   WITH SUBJECT = 'For xp_cmdshell privileges',
   START_DATE = '20020101', EXPIRY_DATE = '20300101';
GO

-- Create a login for the certificate.
CREATE LOGIN xp_cmdshell_cert_login FROM CERTIFICATE xp_cmdshell_cert;
CREATE USER xp_cmdshell_cert_login;
GRANT EXECUTE ON dbo.xp_cmdshell TO xp_cmdshell_cert_login;
GO

-- Copy cert to user database
DECLARE @cert_id int = cert_id('xp_cmdshell_cert')
DECLARE @public_key  varbinary(MAX) = certencoded(@cert_id),
        @private_key varbinary(MAX) =
           certprivatekey(@cert_id,
              'All you need is love',
              'All you need is love')

SELECT @cert_id, @public_key, @private_key

DECLARE @sql nvarchar(MAX) =
      'CREATE CERTIFICATE xp_cmdshell_cert
       FROM  BINARY = ' + convert(varchar(MAX), @public_key, 1) + '
       WITH PRIVATE KEY (BINARY = ' +
          convert(varchar(MAX), @private_key, 1) + ',
          DECRYPTION BY PASSWORD = ''All you need is love'',
          ENCRYPTION BY PASSWORD = ''All you need is love'')'

EXEC YourUserDatabase.sys.sp_executesql @sql;

ALTER CERTIFICATE xp_cmdshell_cert REMOVE PRIVATE KEY;
GO

USE YourUserDatabase;
GO

CREATE PROC dbo.CreateFile
AS
EXEC master..xp_cmdshell 'echo hello > c:\file.txt';
EXEC master..xp_cmdshell 'echo appended data >> c:\file.txt';
EXEC master..xp_cmdshell 'echo more data >> c:\file.txt';
GO
ADD SIGNATURE TO dbo.CreateFile BY CERTIFICATE xp_cmdshell_cert
   WITH PASSWORD = 'All you need is love';
GRANT EXEC ON dbo.CreateFile TO YourUserOrRole;
GO
ALTER CERTIFICATE xp_cmdshell_cert REMOVE PRIVATE KEY;
GO
Run Code Online (Sandbox Code Playgroud)