SQL Server et sécurité : Autoriser et sécuriser les accès cross-databases à l’aide des propriétaires de bases de données

Je travaille de plus en plus souvent dans des environnements dans lesquels la sécurité est devenue primordiale. L’accès entre différentes bases de données dans une instance SQL Server par exemple est plutôt simple à mettre en place dans un cas classique. Il suffit de donner les droits adéquats pour le compte de connexion sur les 2 bases de données concernées  au travers des utilisateurs associés. Seulement les choses se compliquent si l’on veut sécuriser ces accès « cross-databases ». En d’autres termes si on veut que ce même compte de connexion ne puisse accéder aux objets de la base de données B qu’au travers d’objets dans la base de données A sans que celui-ci ne possède de droits explicites dans la base de données B il va falloir utiliser d’autres outils que proposent SQL Server.

Pour illustrer notre propos voici la situation initiale :

image

 

L’idée est la suivante : un utilisateur (test_execute) doit pouvoir accéder via la procédure stockée sp_test depuis la base TEST2 à la table t_test2 dans la base TEST2. La façon la plus naturelle qui nous vient à l’esprit est de créer un utilisateur (test_execute) sur la base de données TEST2, de lui donner les privilèges nécessaires pour accéder à la table TEST2. Le compte de connexion test_execute possède donc 2 utilisateurs dans chaque base de données avec les droits nécessaires. Le script suivant permet de reproduire notre situation.

– Création d’un login test_login qui sera propriétaire de la base de données TEST1
CREATE LOGIN test_login
WITH PASSWORD = ‘P@ssw0rd’,
CHECK_POLICY = OFF,
CHECK_EXPIRATION = OFF;
GO

– Création d’un login test_execute qui pourra exécuter la procédure stockée sp_test
– dans la base de données TEST1
CREATE LOGIN test_execute
WITH PASSWORD = ‘P@ssw0rd’,
CHECK_POLICY = OFF,
CHECK_EXPIRATION = OFF;
GO

– Création base test + table t_test
CREATE DATABASE TEST1;
GO

– Paramétrage du propriétaire de la base de données TEST1
ALTER AUTHORIZATION ON DATABASE::TEST1 TO test_login;
GO
 
USE TEST1
GO
 
CREATE TABLE t_test ( col1 int );
GO

– Création d’un utilisateur test_execute associé au login test_execute dans la base de données TEST1
CREATE USER test_execute FOR LOGIN test_execute;
GO

– Procédure stockée sp_test avec une requête cross-database vers TEST2
CREATE PROC sp_test
AS
  SELECT * FROM test2.dbo.t_test2
GO

– Paramètrage du privilège EXECUTE pour l’utilisateur test_execute vers la procédure stockée sp_test
GRANT EXECUTE ON sp_test TO test_execute;
GO

– Création base test2 + table t_test2
CREATE DATABASE TEST2;
GO
 
USE TEST2;
GO
 
CREATE TABLE t_test2 ( col1 int );
GO

INSERT t_test2 VALUES (1);
GO

– Création d’un utilisateur test_execute mappé au login test_execute
CREATE USER test_execute FOR LOGIN test_execute;
GO

– Paramètrage du privilège SELECT pour l’utilisateur test_execute vers la table t_test2
GRANT SELECT ON t_test2 TO test_execute;
GO

 

Le test avec notre login  test_execute est concluant :

image

L’exécution de la procédure stockée a réussie. Seulement comme je l’ai expliqué ci-dessus ce paramétrage ne va pas forcément convenir selon les contraintes de sécurité en vigueur. En effet, dans le cas présent notre utilisateur a un accès direct aux 2 bases de données TEST1 et TEST2 et ce n’est pas forcément ce que l’on veut ici. La demande initiale est que notre utilisateur puisse avoir accès aux données de la table t_test2 dans la base de données TEST2 depuis la procédure stockée sp_test dans la base de donnes TEST1. Comment réalise-t-on cela ? On peut utiliser pour notre besoin :

  • Passer par les propriétaires de bases de données
  • Utiliser un certificat pour pouvoir utiliser un contexte de sécurité différent lors de l’exécution de la procédure stockée

Dans ce premier billet nous verrons la méthode de passage par les propriétaires de bases de données. Bien entendu avant de continuer nous allons supprimer l’accès à la base de données TEST2 pour notre utilisateur.

USE TEST2;
GO

DROP USER test_execute;
GO

L’exécution de la procédure stockée par notre utilisateur provoque maintenant une erreur :

image

 

icon_arrow Utilisation des propriétaires de bases de données

La méthode consiste à passer par les propriétaires de bases de données en changeant le contexte de sécurité de notre utilisateur lors de l’exécution de la procédure stockée sp_test. Pour cela les prérequis qui devront être appliqués sont les suivants :

  • Une modification de la procédure stockée sp_test pour utiliser le mécanisme de changement de contexte via la clause WITH EXECUTE AS
  • Un utilisateur test_user associé à notre compte de connexion test_login (le propriétaire de la base de données TEST1) et qui devra être créé dans la base de données cible TEST2 et être considéré comme de confiance par cette dernière. Pour cela il faudra donner le privilège AUTHENTICATE à l’utilisateur test_user.
  • Paramétrer les privilèges adéquats sur les objets de base concernés pour cet utilisateur. Dans notre cas il faudra donner le droit SELECT sur la table t_test2 dans la base de données TEST2.
  • Enfin il faudra activer l’option de bases de données TRUSTWORTHY qui indiquera à l’instance SQL Server d’approuver la base de données TEST1 et son contenu, ce qui permettra l’exécution de modules en dehors de la base de données TEST1. Par défaut cette option est désactivée pour des raisons évidentes de sécurité.

 

image

 

Modifions tout d’abord la procédure stockée sp_test pour pouvoir utiliser le changement de contexte pendant l’exécution via la clause WITH EXECUTE AS. Ensuite nous ajouterons 2 vues systèmes sys.user_token et sys.login_token pour visualiser les jetons de contexte de niveau base de données et de niveau serveur. 

USE TEST1;
GO

ALTER PROC sp_test
WITH EXECUTE AS OWNER
AS
  SELECT * FROM sys.user_token;
  SELECT * FROM sys.login_token;
 
  SELECT * FROM test2.dbo.t_test2
GO

Ensuite créons et paramétrons les principaux nécessaires à l’exécution de la procédure stockée sp_test dans la base de données TEST2 :

USE TEST2;
GO

– Création d’un utilisateur test_user_authenticate associé au compte de connexion test_login
CREATE USER test_user FOR LOGIN test_login;
GO

– Privilège AUTHENTICATE pour l’utilisateur test_user_authenticate (authentificateur)
GRANT AUTHENTICATE TO test_user;
GO

– Privilège SELECT pour l’utilisateur test_user_authenticate
GRANT SELECT ON t_test2 TO test_user;
GO

 

Enfin activons l’option TRUSWORTHY dans la base de données TEST1 :

ALTER DATABASE TEST1 SET TRUSTWORTHY ON;
GO

On peut maintenant exécuter la procédure stockée sp_test avec notre login test_execute.

USE TEST1;
GO

SELECT SUSER_NAME() AS login_name, USER_NAME() AS [user_name]
GO

SELECT * FROM sys.user_token;
SELECT * FROM sys.login_token;
GO

EXEC dbo.sp_test;
GO

qui donne les résultats suivants :

image

image

Notre procédure stockée s’est bien exécutée (col1 = 1). Je voulais également souligner quelques points intéressants : nous avons récupéré les jetons au niveau utilisateur (sys.user_token) et au niveau serveur (sys.login_token)  avant et pendant l’exécution de la procédure stockée sp_test.

  • Avant exécution nous pouvons constaté que l’utilisateur utilisé est bien test_execute
  • Pendant l’exécution de la procédure stockée on voit que le contexte a changé comme prévu. Cependant je voulais souligner ici est que d’autres principals entraient en jeu dans notre contexte d’exécution, à savoir l’utilisateur spécial dbo au niveau base de données et le compte de connexion test_login qui est propriétaire de la base de données TEST1 et qui joue le rôle d’authentificateur au niveau serveur. Ceci illustre bien note scénario de changement de contexte par les propriétaires de bases de données.

Nous avons vu ici comment accéder à des objets distants via du code entre bases de données en utilisant la méthode de changement de contexte via les propriétaires de bases de données. Cette méthode présente les avantages suivants :

  • Il n’y a pas besoin de connaitre les mécanismes de chiffrement utilisés par la méthode de changement de contexte à base de certificat
  • La granularité n’est pas aussi fine que pour la méthode à base de certificat. En effet on passe ici par les propriétaires de bases de données, ce qui signifie que nous sommes au niveau bases de données et qu’implicitement n’importe quel module peut utiliser ce mécanisme.
  • L’activation de l’option TRUSTWORTHY n’est pas sans conséquence au niveau de la sécurité. Paradoxalement nous voulons fermer les accès non maitrisés entre bases de données mais nous ouvrons également une brèche que Christophe Laporte explique bien dans ce billet.

Dans un prochain billet j’expliquerai l’approche à base de certificat.

Bonne sécurisation de vos accès !!

David BARBARIN (Mikedavem)
MVP SQL Server

Laisser un commentaire