J'ai créé un rôle dans ma base de données SQL Server 2012 actuelle avec db_datareader
, db_datawriter
, et execute
autorisations. Une procédure dans les appels DB actuels sp_start_job
dans msdb.
Comment accéder à l'accès à mon rôle de base de données pour exécuter la procédure dans MSDB?
J'ai essayé d'exécuter la procédure dans ma base de données actuelle qui appelle sp_start_job
En tant que propriétaire et utilisateur qui est membre, le rôle défini par l'utilisateur n'est toujours pas en mesure d'exécuter la procédure.
J'ai fait le rôle de serveur public
pour la connexion et la mappe sur la base de données MSDB, mais je ne suis pas en mesure d'accorder la permission. Le commandement que j'essaie d'exécuter est:
GRANT EXECUTE ON OBJECT::[msdb].[dbo].[sp_start_job] TO [db_executor]
Lorsque j'exécute de MSDB, l'erreur que je reçois est:
Impossible de trouver l'utilisateur 'db_executor', car il n'existe pas ou que vous n'ayez pas la permission '.
Lorsque j'exécute de la base de données dans laquelle le rôle défini par l'utilisateur, db_executor
est créé, il jette cette erreur:
Vous ne pouvez accorder que ou révoquer des autorisations sur des objets de la base de données actuelle.
Je ne veux pas ajouter d'utilisateurs à SQLAgentOperatorRole
. L'idée est de regrouper tous les utilisateurs d'un seul rôle dans la base de données de l'application et les membres de ce rôle devraient pouvoir exécuter une procédure dans la base de données qui appelle sp_start_job
.
Voici les étapes que vous devriez suivre:
Utilisez un script similaire à celui suivant (mais choisissez d'abord un rôle de MSDB spécifique) pour réaliser ce que vous demandez:
USE [master]
GO
CREATE LOGIN [DOMAIN\user] FROM WINDOWS
GO
USE [msdb]
GO
CREATE USER [DOMAIN\user] FOR LOGIN [DOMAIN\user]
GO
USE [msdb]
GO
EXEC sp_addrolemember N'SQLAgentOperatorRole', N'DOMAIN\user'
GO
Cela peut être accompli sans donner l'application presque complets sur les emplois SQL Agent. Au lieu de créer l'utilisateur dans msdb
, vous créez un certificat dans la DB actuelle et dans msdb
et quelques étapes supplémentaires associées au certificat. Les étapes à suivre sont affichées dans l'exemple de travail ci-dessous:
Configuration initiale et test 1:
USE [master];
---
CREATE DATABASE [SecureJobStarter] COLLATE Latin1_General_100_CI_AS_SC;
CREATE LOGIN [CannotStartJob]
WITH PASSWORD = N'YouCallThisAPassword?',
DEFAULT_DATABASE = [master],
CHECK_EXPIRATION = OFF,
CHECK_POLICY = OFF;
GO
---
USE [SecureJobStarter];
GO
CREATE PROCEDURE [dbo].[StartJob]
(
@JobName sysname
)
AS
SET NOCOUNT ON;
EXEC [msdb].[dbo].[sp_start_job] @job_name = @JobName;
GO
---
CREATE ROLE [JobStarter];
GRANT EXECUTE ON [dbo].[StartJob] TO [JobStarter];
CREATE USER [CannotStartJob] FOR LOGIN [CannotStartJob];
ALTER ROLE [JobStarter] ADD MEMBER [CannotStartJob];
GO
----------------------
-- TEST 1
USE [SecureJobStarter];
EXECUTE AS LOGIN = N'CannotStartJob';
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
EXEC(N'USE [msdb]; EXEC msdb.dbo.sp_start_job @job_name = N''StartJobTest'';');
/*
Msg 229, Level 14, State 5, Procedure sp_start_job, Line xxxxx
The EXECUTE permission was denied on the object 'sp_start_job',
database 'msdb', schema 'dbo'.
*/
EXECUTE [dbo].[StartJob] N'StartJobTest';
/*
Msg 229, Level 14, State 5, Procedure sp_start_job, Line xxxxx
The EXECUTE permission was denied on the object 'sp_start_job',
database 'msdb', schema 'dbo'.
*/
REVERT;
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
GO
----------------------
Comme vous pouvez le constater, il n'existe actuellement aucune possibilité d'exécuter sp_start_job
, soit directement dans [msdb]
(que la connexion a au moins accès à entrer), ou via la procédure stockée locale.
Créez un certificat et un utilisateur basé sur le certificat et Test 2:
USE [SecureJobStarter];
DECLARE @SQL2 NVARCHAR(MAX);
SET @SQL2 = N'
-- Create in current DB...
CREATE CERTIFICATE [Permission:AgentOperator$Cert]
ENCRYPTION BY PASSWORD = N''MyCertificate!MineMineMine!''
WITH SUBJECT = N''Grant the SQLAgentOperatorRole Role'',
EXPIRY_DATE = ''2099-12-31'';
DECLARE @CertificateBytes VARBINARY(MAX),
@PrivateKeyBytes VARBINARY(MAX),
@CertID INT;
SET @CertID = CERT_ID(N''Permission:AgentOperator$Cert'');
SELECT @CertificateBytes = CERTENCODED(@CertID),
@PrivateKeyBytes = CERTPRIVATEKEY(@CertID,
N''MyCertificate!MineMineMine!'', N''MyCertificate!MineMineMine!'');
-- Now recreate same Cert in [msdb]...
USE [msdb];
DECLARE @SQL3 NVARCHAR(MAX);
SET @SQL3 = N''
--------------------------------
CREATE CERTIFICATE [Permission:AgentOperator$Cert]
FROM BINARY = '' + CONVERT(NVARCHAR(MAX), @CertificateBytes, 1) + N''
WITH PRIVATE KEY
(
BINARY = '' + CONVERT(NVARCHAR(MAX), @PrivateKeyBytes, 1) + N'',
DECRYPTION BY PASSWORD = N''''MyCertificate!MineMineMine!'''',
ENCRYPTION BY PASSWORD = N''''MyCertificate!MineMineMine!''''
);
--------------------------------
'';
EXEC(@SQL3);
CREATE USER [Permission:AgentOperator$User]
FROM CERTIFICATE [Permission:AgentOperator$Cert];
ALTER ROLE [SQLAgentOperatorRole]
ADD MEMBER [Permission:AgentOperator$User];
';
EXEC(@SQL2);
----
-- Finally, link the stored procedure in the current DB with the Certificate-based
-- User in [msdb] by signing the stored procedure...
ADD SIGNATURE
TO [dbo].[StartJob]
BY CERTIFICATE [Permission:AgentOperator$Cert]
WITH PASSWORD = N'MyCertificate!MineMineMine!';
GO
----------------------
-- TEST 2
USE [SecureJobStarter];
EXECUTE AS LOGIN = N'CannotStartJob';
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
EXEC(N'USE [msdb]; EXEC msdb.dbo.sp_start_job @job_name = N''StartJobTest'';');
/*
Msg 229, Level 14, State 5, Procedure sp_start_job, Line xxxxx
The EXECUTE permission was denied on the object 'sp_start_job',
database 'msdb', schema 'dbo'.
*/
EXECUTE [dbo].[StartJob] N'StartJobTest';
/*
Msg 14262, Level 16, State 1, Procedure sp_verify_job_identifiers, Line xxxxx
The specified @job_name ('StartJobTest') does not exist.
*/
REVERT;
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
GO
----------------------
Comme vous pouvez le constater ci-dessus, il n'ya toujours aucune possibilité d'exécuter directement sp_start_job
, mais cette fois, la procédure stockée locale est devenue plus loin: elle a pu exécuter sp_start_job
mais a obtenu un Erreur sur une sous-procédure Call - sp_verify_job_identifiers
- Dans sp_start_job
.
Ajouter [Contre] Signatures et Test 3:
Je l'ai initialement installé pour être des signatures contre les comptoirs, mais depuis lors, j'ai appris qu'il n'y a pas de différence pratique entre les signatures régulières et les signatures de comptoir dans ce cas, et aucune différence significative/bénéfique entre eux en général (donc pas sûr de savoir pourquoi il existe même des signatures de comptoir. ). Vous pouvez utiliser des signatures de comptoir ici, mais cela ne semble pas être nécessaire. Ils garantissent simplement que le début du processus est la procédure signée, dbo.StartJob
, telle que l'on ne peut pas démarrer le processus avec les PROC dans [msdb]
. Mais, étant donné que tout le point de faire ce module signature est que l'utilisateur n'a jamais accès à [msdb]
, il n'y avait jamais de potentiel de cette situation de toute façon.
USE [SecureJobStarter];
EXEC(N'
USE [msdb];
ADD COUNTER SIGNATURE -- "COUNTER" keyword to the left should be optional
TO [dbo].[sp_start_job]
BY CERTIFICATE [Permission:AgentOperator$Cert]
WITH PASSWORD = N''MyCertificate!MineMineMine!'';
ADD COUNTER SIGNATURE -- "COUNTER" keyword to the left should be optional
TO [dbo].[sp_verify_job_identifiers]
BY CERTIFICATE [Permission:AgentOperator$Cert]
WITH PASSWORD = N''MyCertificate!MineMineMine!'';
ADD COUNTER SIGNATURE -- "COUNTER" keyword to the left should be optional
TO [dbo].[sp_sqlagent_notify]
BY CERTIFICATE [Permission:AgentOperator$Cert]
WITH PASSWORD = N''MyCertificate!MineMineMine!'';
');
GO
----------------------
-- TEST 3
USE [SecureJobStarter];
EXECUTE AS LOGIN = N'CannotStartJob';
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
EXEC(N'USE [msdb]; EXEC msdb.dbo.sp_start_job @job_name = N''StartJobTest'';');
/*
Msg 229, Level 14, State 5, Procedure sp_start_job, Line xxxxx
The EXECUTE permission was denied on the object 'sp_start_job',
database 'msdb', schema 'dbo'.
*/
EXECUTE [dbo].[StartJob] N'StartJobTest'; -- SUCCESS!!!
/*
"Messages" tab: Job 'StartJobTest' started successfully.
Job History : The job succeeded. The Job was invoked by User CannotStartJob.
*/
REVERT;
SELECT SESSION_USER AS [User], ORIGINAL_LOGIN() AS [OriginalLogin];
GO
----------------------
Comme vous pouvez le constater ci-dessus, il n'ya toujours aucune possibilité d'exécuter directement sp_start_job
, mais cette fois, la procédure stockée locale a réussi :-) !!
Ainsi, bien que cette approche soit certes aussi simple que les 2 lignes nécessaires à l'ajout de la connexion de l'application en tant qu'utilisateur à [msdb]
, puis ajoutez cet utilisateur au rôle, il a l'avantage distinct de ne pas présenter aucun Risques de sécurité. L'utilisateur basé sur le certificat ne peut pas être imitée, et donc la permission d'exécuter sp_start_job
est réellement confinée entièrement à cette procédure stockée locale. Signification: Si vous autorisez l'application Connexion à l'accès à msdb
en créant un utilisateur pour celui-ci, puis ajoutez cet utilisateur au rôle de base de données SQLAgentOperatorRole
, alors que vous connectez non seulement démarrer Job, mais peut faire n'importe quoi que le rôle SQLAgentOperatorRole
permet de donner, abouti à:
(peur, crier et pleurer). Pourquoi? Parce que les développeurs (et des pirates potentiellement) seront en mesure d'avoir le code de l'application do quoi que ce soit Ils veulent (en ce qui concerne les emplois SQL Agent) et ne doivent jamais vous poser à ce sujet, ni même vous parler de Cela (bien que vous découvrirez probablement que quelqu'un soumet un ticket affirmant que cette fonctionnalité ne fait pas ce qu'on leur attendait et que c'était le premier que vous avez entendu parler de cette caractéristique introduite 6-12 mois avant votre Obtenir cette demande de support ;-).
En revanche, l'approche de signature du module (c'est-à-dire à l'aide de certificats et ADD [COUNTER] SIGNATURE
) est très sécurisée. Vous pouvez enregistrer un seul nom d'emploi dans la procédure stockée afin que l'application puisse seulement démarrer celui-ci. Ou, vous pouvez autoriser quelques tâches spécifiques en présentant une procédure stockée accepte un paramètre TINYINT
/INT
CASE
ou IF
pour mapper valeurs 1
, 2
, 3
, ... aux noms d'emploi:
DECLARE @JobName sysname;
SET @JobName = CASE @JobNumber -- input param
WHEN 1 THEN N'this_job'
WHEN 2 THEN N'that_job'
WHEN 3 THEN N'what_job'
END;
EXEC [msdb].[dbo].[sp_start_job] @job_name = @JobName;
Si quelqu'un essaie de devenir sournois et de mettre à jour cette procédure stockée pour faire quelque chose d'autre qui tirerait parti du rôle SQLAgentOperatorRole
, la signature est supprimée et qu'il n'y a plus de lien avec l'utilisateur basé sur le certificat dans msdb
et cette fonctionnalité commence à obtenir une erreur, qui vous revient pour enquêter, ce qui signifie que vous pourrez examiner le changement et si vous n'approuvez pas, vous n'exécutez pas à nouveau ADD SIGNATURE
.
Pour plus d'informations, veuillez consulter les ressources suivantes:
Microsoft a créé des rôles spéciaux qui permettent ce genre de chose
"Rôles de base de données fixes SQL Server Agent"
Accorder EXECUTE
sur sp_start_job
ne fonctionnera pas, car les autorisations et les contrôles effectuées lors du démarrage d'un travail sont liés à appartenance à un rôle seulement.
USE msdb
ALTER ROLE SQLAgentOperatorRole ADD MEMBER DR_user;