Database
 sql >> Base de données >  >> RDS >> Database

Exploration approfondie de la sécurité au niveau des lignes

Présentation

Les organisations sont de plus en plus soucieuses de réduire le coût des licences des solutions de base de données à l'aide de la consolidation. Une certaine consolidation peut être réalisée dans SQL Server simplement en tirant parti de la relation un-à-plusieurs existante entre les instances et les bases de données. Cependant, il existe des cas où la solution exige que les données soient consolidées dans une table. Dans un tel cas, il peut y avoir des inquiétudes quant à la façon de restreindre l'accès aux données.

La sécurité au niveau de la ligne a été introduite dans SQL Server 2016 en tant que solution à des scénarios similaires à ceux ci-dessus. Il vous permet de restreindre l'accès aux lignes d'une table en fonction des conditions définies dans une fonction de valeur de table en ligne appelée fonction de prédicat . Lorsqu'une fonction de prédicat est appliquée à une table utilisateur contenant des données consolidées, le système peut être configuré pour renvoyer différents ensembles de données à différents utilisateurs en fonction de leurs rôles, qui à leur tour dépendent de leurs descriptions de poste ou de leurs services, par exemple.

Scénario

Nous allons construire un scénario simple pour illustrer ce concept en utilisant une institution financière. Une banque a décidé de consolider les comptes de tous ses clients sur une seule base de données et les Transactions table est une seule table partitionnée contenant toutes les transactions, tout comme les Clients table pour stocker tous les clients de la banque. La banque est implantée dans plusieurs pays et est également en pleine expansion. Chaque pays est identifié par un AffiliateID colonne. L'entreprise est structurée de telle sorte que l'accès aux tables clés est limité en fonction de l'ancienneté.

Identifier les éléments sécurisables

Nous devrons mettre en œuvre une solution de sécurité au niveau de la ligne qui restreint l'accès aux données client et transactionnelles en fonction des rôles et d'une politique de sécurité au niveau de la ligne. Notre première étape consiste à créer les tables requises. Le listing 1 montre le DDL pour les tables de clés que nous allons tester. La base de données complète utilisée pour ce test peut être téléchargée ici.

Listing 1 – Core Tables in West African Commercial Bank Database;
-- Customers;
create table Customers
(CustID int identity (1000,1) not null Primary Key
,FirstName varchar(100)
,LastName varchar(100)
,PhoneNo bigint
,ContactAddress varchar(4000)
,AffiliateID char(3) foreign key references Affiliates(AffiliateID)
,AccountNo1 bigint
,AccountNo2 bigint
,AccountNo3 bigint
,AccountNo1Curr char (3)
,AccountNo2Curr char (3)
,AccountNo3Curr char (3)
)
GO

-- Transactions;
create table Transactions
(TranID int identity (1000,1) not null 
,AcctID int foreign key references Accounts (AcctID)
,TranDate datetime 
,TranAmt money
,AffiliateID char(3) foreign key references Affiliates(AffiliateID)
,primary key (TranID,TranDate))
ON PartSch (TranDate)

-- Transaction_History;
create table Transaction_History
(TranID int identity (1000,1) not null 
,AcctID int foreign key references Accounts (AcctID)
,TranDate datetime 
,TranAmt money
,AffiliateID char(3) foreign key references Affiliates(AffiliateID)
,primary key (TranID,TranDate))
ON PartSch (TranDate)

Nous créons ensuite un ensemble de tableaux que nous pouvons utiliser pour identifier le personnel. Dans cette configuration, chaque portée a un ScopeID qui détermine dans quelle mesure il peut visualiser ou manipuler des données :

  1. Nationale – Un membre du personnel ne peut manipuler des données que dans le pays du membre du personnel (où il travaille)
  2. Régional – Un membre du personnel ne peut manipuler les données que dans la région du membre du personnel (par exemple, l'Afrique de l'Ouest)
  3. Mondial – Un membre du personnel peut manipuler des données dans n'importe quel pays où la banque aura une succursale

Chaque périmètre est attribué au personnel en fonction de sa désignation. La portée d'un responsable de groupe est mondiale , le périmètre d'un Country Manager est Régional et la portée d'un exécutif est nationale . La manière traditionnelle de restreindre l'accès aux données est souvent l'utilisation de rôles et d'autorisations. L'attribution d'autorisations à un rôle, puis l'attribution du rôle à un utilisateur signifie que l'utilisateur dispose des autorisations associées à ce rôle pour l'intégralité de l'ensemble de données de la table en question. La sécurité au niveau de la ligne nous donne la possibilité de faire quelque chose de plus précis :restreignez les autorisations SELECT/UPDATE/DELETE de l'utilisateur à un sous-ensemble de l'ensemble de données de la table (contrôle d'accès précis).

Fig. 1. StaffScope et tables de personnel

Rôles et utilisateurs de la base de données

Le listing 2 montre les utilisateurs et les rôles que nous devons créer pour continuer avec notre solution. L'idée est qu'il existe une relation entre le personnel tel qu'il est stocké dans les tables utilisateur Staff et StaffScope et les principaux de la base de données que ce personnel utilisera éventuellement pour accéder aux données. Observez la colonne de la Fig. 1 appelée DBUserID . Cette colonne est remplie à l'aide de la fonction DATABASE_PRINCIPAL_ID (voir Listing 2)

Listing 2 – Staff, Database User IDs and Roles

-- Populate Staff Table
use WACB
go
insert into Staff values ('John','Edu',DATABASE_PRINCIPAL_ID(),'Manager','233205678493','2','Accra, Ghana','EGH');
insert into Staff values ('Margaret','Harrison',DATABASE_PRINCIPAL_ID(),'Group Manager','2348030006574','3','Lagos, Nigeria','ENG');
insert into Staff values ('Edward','Antwi',DATABASE_PRINCIPAL_ID(),'Executive','22824567493','1','Lome, Togo','ETG');
insert into Staff values ('Barbara','Orji',DATABASE_PRINCIPAL_ID(),'Executive','22424567493','1','Abuja, Nigeria','ENG');
GO

-- Create Database User IDs for Staff
create user jedu without login;
create user mharrison without login;
create user eantwi without login;
create user borji without login;

-- Associate Database Principal IDs with Staff
update staff set DBUserID=DATABASE_PRINCIPAL_ID(concat(left(firstname,1),lastname));


-- Create Database Roles
create role [National] ;
create role [Regional] ;
create role [Global] ;

-- Grant Permissions on Desired Tables to Database Roles
grant select on customers to [National];
grant select, update on customers to Regional;
grant select, update on customers to Global;
grant select on Transactions to Regional, Global;
grant select on Transaction_History to Regional, Global;
grant update on Transactions to Global;


-- Grant Database Roles to Database Users Associated with Staff
alter role [National] add member eantwi;
alter role [National] add member borji;
alter role [Regional] add member jedu;
alter role [Global] add member mharrison;

Jusqu'à présent, en résumé, ce que nous avons fait est :

  1. Créer/identifier les tables que nous devons sécuriser
  2. Créer des tableaux qui indiquent les critères que nous utiliserons pour restreindre l'accès aux données au niveau de la ligne (Portée)
  3. Création de rôles de base de données et d'utilisateurs auxquels nous appliquerons des restrictions
  4. Accès restreint aux tables principales ("Table Level Security") à l'aide de rôles et d'autorisations

Fonction de prédiction et politique de sécurité

Jusqu'à présent, nous avons ce que nous pouvons appeler la sécurité au niveau de la table implémentée à l'aide de rôles et d'autorisations. Maintenant, nous voulons aller plus loin. Nous voulons que deux mandataires qui ont des privilèges SELECT sur une table puissent interroger la table mais voient différents ensembles de données en fonction des conditions que nous avons définies. Liste 3 nous montre comment nous y parvenons.

Listing 3 - Implement Row Level Security

-- Create Predicate Function
create schema rls;
go

create function rls.AccessPredicate (@AffiliateID char(3))
returns table
with schemabinding
as
return select 1 as access 
from dbo.Staff as s 
join dbo.StaffScope ss on s.ScopeID=ss.ScopeID 
join dbo.Affiliates a on s.AffiliateID=a.AffiliateID
where (
IS_MEMBER('National')=1
and s.DBUserID=DATABASE_PRINCIPAL_ID()
and @AffiliateID=s.AffiliateID
)
OR
(
IS_MEMBER('Regional')=1
and @AffiliateID in (select a.AffiliateID from dbo.Affiliates where Region='West Africa')
)
OR
(
IS_MEMBER('Global')=1
);
GO

-- Create Security Policy
create security policy rls.dataSecurityPol
add filter predicate rls.AccessPredicate (AffiliateID) on dbo.Customers,
add filter predicate rls.AccessPredicate (AffiliateID) on dbo.Transactions,
add filter predicate rls.AccessPredicate (AffiliateID) on dbo.Transaction_History,
add block predicate rls.AccessPredicate (AffiliateID) on dbo.Customers after update,
add block predicate rls.AccessPredicate (AffiliateID) on dbo.Transactions after update,
add block predicate rls.AccessPredicate (AffiliateID) on dbo.Transaction_History after update;
GO

-- Alter Security Policy
alter security policy rls.dataSecurityPol
add filter predicate rls.AccessPredicate (AffiliateID) on dbo.Transaction_History,
add block predicate rls.AccessPredicate (AffiliateID) on dbo.Transaction_History after update;
GO

La fonction de prédicat définit les conditions qui doivent être remplies pour qu'un principal voie un sous-ensemble des données intéressantes. Dans cette fonction, il y a trois conditions :

  1. L'utilisateur de la base de données du personnel est membre du National rôle et AffiliateID correspond à celle du personnel OU
  2. L'utilisateur de la base de données du personnel est membre du Régional rôle et AffiliateID correspond à la liste des AffiliateID appartenant à la Région Afrique de l'Ouest OU
  3. L'utilisateur de la base de données de l'équipe est membre de Global

Cela implique qu'un membre du Global rôle voit toutes les données simplement parce qu'il appartient à ce rôle. Cependant, les membres des deux autres rôles doivent remplir des critères supplémentaires à la limite des AffiliateIDs .

Pour que la fonction soit utile, appliquez-la aux tables en tant que prédicats FILTER ou prédicats BLOCK. Les prédicats FILTER limitent ce que le principal peut voir tandis que les prédicats BLOCK garantissent que le principal ne peut pas manipuler de données en dehors de celles qui lui sont présentées par les restrictions définies dans la fonction. Une politique de sécurité est un conteneur dans lequel nous spécifions les prédicats FILTER et BLOCK pour toutes les tables qui nous intéressent. Jetez un œil à la Liste 3 à nouveau.

Un aspect très intéressant de cette approche est la modularité. Nous pouvons appliquer les prédicats à des tables supplémentaires dans la politique de sécurité sans affecter les tables définies existantes, nous pouvons ajouter de nouveaux principaux de base de données (Staff) en créant des utilisateurs de base de données et en leur accordant les rôles appropriés. En cas de mouvement de personnel, nous pouvons mettre à jour les attributions de rôles, etc.

Tester la mise en œuvre

Alors maintenant que nous avons terminé, nous pouvons emprunter l'identité des principaux de la base de données pour déterminer si nous avons les résultats attendus en utilisant le code de la liste 4. Avant de regarder cela, voyons les rôles associés à chaque personnel et à leurs affiliés dans la figure 2.

Fig. 2. Liste du personnel

Listing 4 – Testing the Implementation

select * from Customers;
execute ('select * from Customers') as user='eantwi';
execute ('select * from Customers') as user='borji';
execute ('select * from Customers') as user='jedu';
execute ('select * from Customers') as user='mharrison';

Dans la première ligne, j'interroge les Clients table en tant qu'administrateur système, mais je n'obtiens AUCUNE LIGNE. Cela signifie que même un administrateur ne peut pas annuler les effets de RLS sans usurpation d'identité.

Fig. 4. SysAdmin ne voit aucune ligne

Barbara et Edward sont tous deux des cadres et appartiennent à la portée nationale, mais ils travaillent dans différents pays, ils voient donc les clients associés à leurs affiliés respectifs. (Voir les noms des portées dans la Fig. 1).

Fig. 5. Les dirigeants voient les lignes de leur affilié

John et Margaret sont directeurs de pays et de groupe. Ils appartiennent au Régional et Global Champs d'application respectivement. John voit des données pour l'Afrique de l'Ouest, tandis que Margaret voit des données pour toutes les régions.

Fig. 6. Les managers voient les lignes de leur région

Les résultats sont les mêmes pour toutes les autres tables auxquelles la politique de sécurité a été appliquée. Observez que sans autorisations sur les Transactions table, la sécurité au niveau de la ligne n'a aucune valeur.

Fig. 7. Aucune autorisation SELECT sur les transactions Tableau

Listing 5 – Permissions on Transactions Table
grant select on dbo.Transactions to [National];

Fig. 8. Transactions Tableau vu par les dirigeants

Conclusion

Row Level Security est une méthode puissante d'exploitation de la capacité de contrôle d'accès à grain fin de SQL Server. L'utilisation de cette fonctionnalité nécessite que vous exécutiez SQL Server 2016 ou une version ultérieure. Comme son nom l'indique, l'objectif est de restreindre l'accès aux lignes d'une table à l'aide de requêtes complexes après avoir pris en charge la "sécurité au niveau de la table". Les scénarios dans lesquels cette capacité peut être appliquée sont infinis, elle est donc très utile pour un large éventail d'environnements. Faites bien d'explorer et de voir ce qu'il peut faire pour vous.

Références

En ligneIsakov, V. (2018). Réf 70-764 de l'examen Administration d'une infrastructure de base de données SQL . Éducation Pearson

Sécurité au niveau de la ligne