使用散列密码编写应用程序角色的脚本

Han*_*non 8 security sql-server role scripting

我需要使用散列密码编写应用程序角色的脚本,以便我可以将它从一个数据库复制到另一个数据库。

考虑以下示例代码,它使用应用程序角色为不受信任的用户提供提升的访问权限:

USE tempdb;

CREATE LOGIN LimitedLogin
WITH PASSWORD = 'Password1'
    , CHECK_POLICY = OFF
    , CHECK_EXPIRATION = OFF;

CREATE USER LimitedLogin
FOR LOGIN LimitedLogin
WITH DEFAULT_SCHEMA = dbo;

CREATE APPLICATION ROLE MyAppRole
WITH PASSWORD = 'Password2'
    , DEFAULT_SCHEMA = dbo;

EXEC sp_addrolemember @rolename = 'db_datareader'
    , @membername = 'MyAppRole';

CREATE TABLE dbo.Numbers
(
    [Number] int CONSTRAINT PK_Numbers 
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1) NOT NULL
);

INSERT INTO dbo.Numbers
VALUES (1)
    , (2);

GO
Run Code Online (Sandbox Code Playgroud)

一旦我们在 tempdb 中创建了测试设置,我们就可以以[LimitedLogin]用户身份登录,并运行以下命令:

-- login as [LimitedLogin]

USE tempdb;

SELECT *
FROM dbo.Numbers;
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,返回以下错误:

Msg 229, Level 14, State 5, Line 1
The SELECT permission was denied on the object 'Numbers'
    , database 'Test', schema 'dbo'.
Run Code Online (Sandbox Code Playgroud)

但是,一旦我们sp_setapprole使用适当的密码执行,我们可以从dbo.Numbers表中看到所需的结果:

DECLARE @cookie VARBINARY(8000);
EXEC sp_setapprole @rolename = 'MyAppRole'
    , @password = 'Password2'
    , @fCreateCookie = 1
    , @cookie = @cookie OUT;
SELECT @cookie;

SELECT TOP(10) *
FROM dbo.Numbers;

EXEC sp_unsetapprole @cookie = @cookie;
Run Code Online (Sandbox Code Playgroud)

我希望能够通过从源数据库编写脚本来自动创建应用程序角色以应用于目标数据库。我可以通过以下方式轻松执行大部分操作:

SELECT 'CREATE APPLICATION ROLE ' + QUOTENAME(dp.name) + '
WITH PASSWORD = ''xxxx''
    , DEFAULT_SCHEMA = ' + QUOTENAME(dp.default_schema_name) + ';'
FROM sys.database_principals dp
WHERE dp.type_desc = 'APPLICATION_ROLE';
Run Code Online (Sandbox Code Playgroud)

但是,我真的很希望能够在脚本中使用散列密码,例如:

CREATE APPLICATION ROLE [MyAppRole]
WITH PASSWORD = 0x12345678 HASHED
    , DEFAULT_SCHEMA = [dbo];
Run Code Online (Sandbox Code Playgroud)

这可能吗?据推测,应用程序角色密码的散列版本存储在数据库中的某处

使用 SQL Server Management Studio 的“脚本到 ->”功能,应用程序角色使用密码编写脚本,如下所示:

/****** Object:  ApplicationRole [MyAppRole]    Script Date: 9/22/2015 10:18:12 AM ******/
/* To avoid disclosure of passwords, the password is generated in script. */
declare @idx as int
declare @randomPwd as nvarchar(64)
declare @rnd as float
select @idx = 0
select @randomPwd = N''
select @rnd = rand((@@CPU_BUSY % 100) + ((@@IDLE % 100) * 100) + 
       (DATEPART(ss, GETDATE()) * 10000) + ((cast(DATEPART(ms, GETDATE()) as int) % 100) * 1000000))
while @idx < 64
begin
   select @randomPwd = @randomPwd + char((cast((@rnd * 83) as int) + 43))
   select @idx = @idx + 1
select @rnd = rand()
end
declare @statement nvarchar(4000)
select @statement = N'CREATE APPLICATION ROLE [MyAppRole] WITH DEFAULT_SCHEMA = [dbo], ' + N'PASSWORD = N' + QUOTENAME(@randomPwd,'''')
EXEC dbo.sp_executesql @statement
GO
Run Code Online (Sandbox Code Playgroud)

显然,这对我来说没有帮助,尽管它确实提供了一种有趣的生成随机密码的方法。


根据到目前为止的答案,我创建了一个 Connect 建议,以在产品中添加对此的支持:

Aar*_*and 6

您可以使用 DAC(专用管理员连接)进行连接,然后passwordsys.sysowners. 首先,使用连接:

ADMIN:Server\Instance
Run Code Online (Sandbox Code Playgroud)

然后:

SELECT password_hash = [password]
  FROM sys.sysowners
  WHERE name = N'MyAppRole';
Run Code Online (Sandbox Code Playgroud)

该视图使用DAC时才可见,列未在该父视图暴露可见的(sys.database_principals)。当然,请小心使用 DAC。

都说了,这对你没有帮助。CREATE APPLICATION ROLE与 有很大不同CREATE LOGIN,因为您不能提供散列密码,只能提供纯文本。甚至不要考虑对散列值进行逆向工程,因为现代版本的 SQL Server 使用精心设计的方法来加密密码。事实上,如果你自己尝试这个,你会看到每次都会创建不同的哈希,即使是在同一个语句中:

SELECT PWDENCRYPT(N'foo'), PWDENCRYPT(N'foo');
Run Code Online (Sandbox Code Playgroud)

结果(这次在我的机器上),请注意您的结果会有所不同:

0x0200185968C35F22AF70...   0x0200D6C77A1D84A8467F...
Run Code Online (Sandbox Code Playgroud)

所以,我会推荐:

  1. 将应用程序密码存储在源代码管理中的某处,或者您当前存储其他系统密码的任何地方,并使用它来生成脚本以将应用程序角色部署到另一台服务器(或源代码管理整个CREATE APPLICATION ROLE脚本);或者,
  2. 使用常规角色而不是应用程序角色。