Introduktion
Organisationer bliver mere og mere bekymrede over, hvordan de kan reducere omkostningerne ved at licensere databaseløsninger ved hjælp af konsolidering. En vis konsolidering kan opnås i SQL Server blot ved at udnytte det eksisterende en-til-mange forhold mellem instanser og databaser. Der er dog tilfælde, hvor løsningen kræver, at data samles i én tabel. I et sådant tilfælde kan der være bekymringer om, hvordan man begrænser adgangen til dataene.
Row Level Security blev introduceret i SQL Server 2016 som en løsning på scenarier svarende til ovenstående. Det giver dig mulighed for at begrænse adgangen til rækker i en tabel baseret på betingelser, der er defineret i en indlejret tabelværdifunktion kaldet en prædikatfunktion . Når en prædikatfunktion anvendes på en brugertabel, der indeholder konsoliderede data, kan systemet konfigureres til at returnere forskellige datasæt til forskellige brugere afhængigt af deres roller, hvilket igen afhænger af deres jobbeskrivelser eller afdelinger for eksempel.
Scenarie
Vi skal bygge et simpelt scenarie for at illustrere dette koncept ved hjælp af en finansiel institution. En bank har besluttet at samle konti for alle sine kunder i en enkelt database og Transaktioner tabel er en enkelt opdelt tabel, der indeholder alle transaktioner, ligesom Kunderne er bord til opbevaring af alle bankens kunder. Banken er placeret i flere lande og ekspanderer også. Hvert land er identificeret med et AffiliateID kolonne. Virksomheden er struktureret således, at adgangen til nøgletabeller er begrænset ud fra anciennitet.
Identificer sikkerhedsobjekter
Vi skal implementere en Row Level Security-løsning, der begrænser adgangen til kunde- og transaktionsdata baseret på roller og en Row Level Security-politik. Vores første skridt er at oprette de nødvendige tabeller. Liste 1 viser DDL for de nøgletabeller, vi skal teste. Hele databasen brugt til denne test kan downloades herfra.
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)
Vi opretter derefter et sæt tabeller, som vi kan bruge til at identificere personale. I denne opsætning har hver medarbejder et ScopeID som bestemmer i hvilket omfang han eller hun kan se eller manipulere data:
- National – En medarbejder kan kun manipulere data i den ansattes land (hvor han eller hun arbejder)
- Regional – En medarbejder kan kun manipulere data i den ansattes region (f.eks. Vestafrika)
- Global – En medarbejder kan manipulere data i ethvert land, hvor banken nogensinde vil have en filial
Hvert scope tildeles personalet ud fra deres udpegelse. En gruppeleders omfang er globalt , en landechefs omfang er Regional og en Executives omfang er National . Den traditionelle måde at begrænse adgangen til data på er ofte brugen af roller og tilladelser. At tildele tilladelser til en rolle og efterfølgende tildele rollen til en bruger betyder, at brugeren har de tilladelser, der er knyttet til denne rolle for hele datasættet i den pågældende tabel. Row Level Security giver os mulighed for at gøre noget mere detaljeret:begrænse brugerens SELECT/UPDATE/DELETE-tilladelser til en delmængde af datasættet i tabellen (finmasket adgangskontrol).
Fig. 1. StaffScope og Staff Tables
Databaseroller og -brugere
Liste 2 viser de brugere og roller, vi skal oprette for at fortsætte med vores løsning. Tanken er, at der er et forhold mellem personalet som gemt i brugertabeller Staff og StaffScope og de Database Principals, som disse medarbejdere på sigt vil bruge til at få adgang til dataene. Se kolonnen i fig. 1 kaldet DBUserID . Denne kolonne udfyldes med funktionen DATABASE_PRINCIPAL_ID (se liste 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;
Indtil videre er det opsummerende, hvad vi har gjort:
- Opret/identificer de tabeller, vi skal sikre
- Opret tabeller, der angiver de kriterier, vi skal bruge til at begrænse adgangen til data på rækkeniveau (Scope)
- Oprettede databaseroller og brugere skal vi anvende begrænsninger på
- Begrænset adgang til kernetabellerne ("Sikkerhed på tabelniveau") ved hjælp af roller og tilladelser
Forudsigelsesfunktion og sikkerhedspolitik
Indtil videre har vi, hvad vi kan kalde Table Level Security, implementeret ved hjælp af roller og tilladelser. Nu vil vi gå dybere. Vi ønsker, at to principaler, der har SELECT-rettigheder på en tabel, skal kunne forespørge i tabellen, men se forskellige datasæt baseret på betingelser, som vi har sat op. Fortegnelse 3 viser os, hvordan vi opnår dette.
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
Prædikatfunktionen definerer de betingelser, der skal være opfyldt, for at en principal kan se en delmængde af de interessante data. I denne funktion er der tre betingelser:
- Stabets databasebruger er medlem af National rolle og AffiliateID svarer til personalet ELLER
- Stabets databasebruger er medlem af Regional rolle og AffiliateID matcher listen over AffiliateID tilhører den vestafrikanske region OR
- Stabets databasebruger er medlem af Global
Dette indebærer, at et medlem af Global rollen ser alle data, simpelthen fordi han eller hun tilhører den rolle. Medlemmer af de to andre roller skal dog opfylde yderligere kriterier, der grænser op til AffiliateID'erne .
For at funktionen skal være nyttig, skal du anvende dette på tabeller som enten FILTER-prædikater eller BLOCK-prædikater. FILTER-prædikater begrænser, hvad principalen kan se, mens BLOCK-prædikater sikrer, at principalen ikke kan manipulere nogen data uden for det, som præsenteres for ham/hende af de begrænsninger, der er defineret i funktionen. En sikkerhedspolitik er en beholder, hvori vi angiver FILTER- og BLOCK-prædikaterne for alle tabeller, vi er interesserede i. Tag et kig på List 3 igen.
Et meget interessant aspekt ved denne tilgang er modulariteten. Vi kan anvende prædikaterne på yderligere tabeller i sikkerhedspolitik uden at påvirke de eksisterende definerede tabeller, vi kan tilføje nye databaseprincipper (Staff) ved at oprette databasebrugere og tildele dem de passende roller. Når der sker personalebevægelser, kan vi opdatere rolletildelingerne og så videre.
Test af implementeringen
Så nu, hvor vi er færdige, kan vi efterligne databaseprincipperne for at afgøre, om vi har de forventede resultater ved hjælp af koden i liste 4. Inden vi ser på det, lad os se de roller, der er forbundet med hver medarbejder og deres tilknyttede selskaber i fig. 2.
Fig. 2. Personaleliste
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';
I den første linje forespørger jeg Kunderne tabel som en sysadmin, men jeg får INGEN RÆKKER. Det betyder, at selv en administrator ikke kan tilsidesætte virkningerne af RLS uden efterligning.
Fig. 4. SysAdmin ser ingen rækker
Barbara og Edward er begge ledere og tilhører National Scope, men de arbejder i forskellige lande, så de ser kunderne forbundet med deres respektive datterselskaber. (Se personalenavne i fig. 1).
Fig. 5. Ledere ser deres affilieredes rækker
John og Margaret er lande- og gruppeledere. De tilhører Regional og Global Omfang hhv. John ser data for Vestafrika, mens Margaret ser data for alle regioner.
Fig. 6. Ledere ser deres regions rækker
Resultaterne er de samme for alle andre tabeller, som sikkerhedspolitikken er blevet anvendt på. Bemærk det uden tilladelser på Transaktioner tabel, Row Level Security er uden værdi.
Fig. 7. Ingen SELECT-tilladelser på Transaktioner tabel
Listing 5 – Permissions on Transactions Table grant select on dbo.Transactions to [National];
Fig. 8. Transaktioner Tabel set af ledere
Konklusion
Row Level Security er en kraftfuld metode til at udnytte SQL Servers finkornede adgangskontrolkapacitet. Brug af denne funktion kræver, at du kører SQL Server 2016 eller nyere. Som navnet antyder, er målet at begrænse adgangen til rækker i en tabel ved hjælp af komplekse forespørgsler, efter at du har sørget for "tabelniveausikkerhed". Scenarierne, hvor denne funktion kan anvendes, er uendelige, så den er meget nyttig til en lang række miljøer. Gør klogt i at udforske og se, hvad det kan gøre for dig.
Referencer
Isakov, V. (2018). Eksamen Ref 70-764 Administration af en SQL-databaseinfrastruktur . Pearson Education
Sikkerhed på rækkeniveau