登錄是服務器級別的對象,因此需要服務器級別權限。 EXECUTE AS <database-user>
是一個數據庫範圍的安全上下文。
通過存儲過程授予普通用戶特權操作的一種方法是使用映射到具有必要權限的登錄名的證書對模塊進行簽名。在這種情況下,必要的步驟是:
- 創建主數據庫
- 證書爲證
- 授予證書登錄的權限創建登錄
- 出口從主
證書創建登錄
- 將證書導入應用程序數據庫
- 使用證書籤署存儲過程
下面是從Erland Sommarskog's web site收集的一個例子。請注意,每次更改證書時,您都需要使用證書退出程序。
--create database master key, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]';
END;
GO
CREATE CERTIFICATE SecurityAdministratorCertificate
WITH
SUBJECT = 'Allows non-privileged users to create and alter logins'
, START_DATE = '20020101'
, EXPIRY_DATE = '20300101';
GO
CREATE LOGIN SecurityAdministratorCertificateLogin
FROM CERTIFICATE SecurityAdministratorCertificate;
GO
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin;
GO
--export cert from master
DECLARE @CERTENC VARBINARY(MAX);
DECLARE @CERTPVK VARBINARY(MAX);
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate'));
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'),
'All you need is love');
DECLARE @sql nvarchar(MAX);
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = '
+ CONVERT(nvarchar(MAX), @CERTENC, 1)
+ ' WITH PRIVATE KEY (BINARY = '
+ CONVERT(nvarchar(MAX), @CERTPVK, 1)
+ ', DECRYPTION BY PASSWORD = ''All you need is love'');'
--import cert into app databases
USE MyDatabase;
--create database master key, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]';
END;
EXEC(@sql);
GO
CREATE PROCEDURE [dbo].[create_login]
@Login [nvarchar](256),
@Password [nvarchar](128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Sql NVARCHAR(4000);
SET @sql = N'CREATE LOGIN ' + QUOTENAME(@Login) + N' WITH PASSWORD = '
+ QUOTENAME(@Password, N'''') + N',CHECK_EXPIRATION=OFF, CHECK_POLICY=ON;';
EXEC (@sql);
END
GO
--grant exec permissions to users
GRANT EXECUTE ON [dbo].[create_login] TO [my_simple_role];
GO
--sign proc with certificate
ADD SIGNATURE TO dbo.create_login BY CERTIFICATE SecurityAdministratorCertificate;
GO
編輯:
上面的例子使用加密數據庫主密鑰而不是特定的證書的密碼證書的私鑰。在還原數據庫或將其附加到不同SQL實例(不還原master數據庫)的情況下,您需要在master數據庫中重新創建服務器級別的對象,包括應用程序所需的所有登錄名和存儲在主。要恢復證書,一種方法是在恢復/附加後將用戶數據庫中的證書複製到主數據庫,然後使用權限重新創建證書登錄名。在這種情況下DMK無法自動打開,因爲在新實例上加密數據庫主密鑰的服務主密鑰不同。需要原始密碼才能在將證書複製到主數據庫的腳本中手動打開DMK。用於在數據庫之間複製證書的證書密碼是臨時的,不需要保留。
這裏是和例子來重新創建一個恢復或附加後掌握證書和證書登錄:
USE MyDatabase;
--open DMK with original password
OPEN MASTER KEY DECRYPTION BY PASSWORD='[email protected]';
--export cert from user database
USE MyDatabase;
DECLARE @CERTENC VARBINARY(MAX);
DECLARE @CERTPVK VARBINARY(MAX);
SELECT @CERTENC = CERTENCODED(CERT_ID(N'SecurityAdministratorCertificate'));
SELECT @CERTPVK = CERTPRIVATEKEY(CERT_ID(N'SecurityAdministratorCertificate'),
'temporary password here');
DECLARE @sql nvarchar(MAX);
SELECT @sql = N'CREATE CERTIFICATE SecurityAdministratorCertificate FROM BINARY = '
+ CONVERT(nvarchar(MAX), @CERTENC, 1)
+ ' WITH PRIVATE KEY (BINARY = '
+ CONVERT(nvarchar(MAX), @CERTPVK, 1)
+ ', DECRYPTION BY PASSWORD = ''temporary password here'');'
SELECT @sql
CLOSE MASTER KEY;
--import cert into master
USE master;
--create database master key in new instance master database, if necessary
IF NOT EXISTS(SELECT 1 FROM sys.symmetric_keys WHERE name = N'##MS_DatabaseMasterKey##')
BEGIN
CREATE MASTER KEY ENCRYPTION BY PASSWORD='[email protected]';
END;
EXEC(@sql);
GO
--recreate login and assign permissions
CREATE LOGIN SecurityAdministratorCertificateLogin
FROM CERTIFICATE SecurityAdministratorCertificate;
GRANT ALTER ANY LOGIN TO SecurityAdministratorCertificateLogin;
GO
出色答卷。謝謝!需要將這兩個密碼中的哪一個存儲在「安全的地方」以供將來使用?我可以在創建數據庫時創建兩個隨機的強臨時密碼,只是爲了讓上面的'create_login'存儲過程起作用嗎? – l33t
@ l33t,用於導出/導入證書的密碼是臨時的,可以是隨機的。數據庫主密鑰密碼應保留以供數據庫恢復或附加到其他SQL實例時使用。 我會添加一些額外的信息給我的答案來更詳細地解釋。 –