Introduzione
Le organizzazioni stanno diventando sempre più preoccupate su come ridurre il costo delle soluzioni di database in licenza utilizzando il consolidamento. È possibile ottenere un certo consolidamento in SQL Server semplicemente sfruttando la relazione uno-a-molti esistente tra istanze e database. Tuttavia, ci sono casi in cui la soluzione richiede che i dati siano consolidati in un'unica tabella. In tal caso, potrebbero esserci dubbi su come limitare l'accesso ai dati.
La sicurezza a livello di riga è stata introdotta in SQL Server 2016 come soluzione per scenari simili a quelli precedenti. Consente di limitare l'accesso alle righe di una tabella in base alle condizioni definite in una funzione con valori di tabella inline denominata Funzione predicata . Quando una funzione predicato viene applicata a una tabella utente contenente dati consolidati, il sistema può essere configurato per restituire set di dati diversi a utenti diversi a seconda dei loro ruoli, che a loro volta dipendono, ad esempio, dalle descrizioni del lavoro o dai reparti.
Scenario
Costruiremo uno scenario semplice per illustrare questo concetto utilizzando un istituto finanziario. Una banca ha deciso di consolidare i conti di tutti i suoi clienti su un unico database e le Transazioni table è una singola tabella partizionata che contiene tutte le transazioni così come i Clienti tabella per la memorizzazione di tutti i clienti della banca. La banca ha sede in diversi paesi ed è anche in espansione. Ogni Paese è identificato da un AffiliateID colonna. L'azienda è strutturata in modo tale che l'accesso alle tabelle chiave sia limitato in base all'anzianità.
Identifica i beni mobili
Dovremo implementare una soluzione di sicurezza a livello di riga che limiti l'accesso ai dati del cliente e delle transazioni in base ai ruoli e a una politica di sicurezza a livello di riga. Il nostro primo passo è creare le tabelle richieste. Il Listato 1 mostra il DDL per le tabelle chiave che testeremo. L'intero database utilizzato per questo test può essere scaricato da qui.
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)
Quindi creiamo una serie di tabelle che possiamo utilizzare per identificare il personale. In questa configurazione, ogni rigo ha un ScopeID che determina in che misura lui o lei può visualizzare o manipolare i dati:
- Nazionale – Un membro dello staff può manipolare i dati solo nel paese del personale (dove lavora)
- Regionale – Un membro dello staff può manipolare i dati solo nella regione del personale (ad es. Africa occidentale)
- Globale – Un collaboratore può manipolare i dati in qualsiasi paese in cui la banca avrà una filiale
Ciascun ambito è assegnato al personale in base alla loro designazione. L'ambito di un Group Manager è Globale , l'ambito di un Country Manager è Regionale e l'ambito di un Executive è Nazionale . Il modo tradizionale per limitare l'accesso ai dati è spesso l'uso di ruoli e autorizzazioni. Assegnare autorizzazioni a un ruolo e successivamente assegnare il ruolo a un utente significa che l'utente dispone delle autorizzazioni associate a quel ruolo per l'intero set di dati nella tabella in questione. La sicurezza a livello di riga ci offre l'opportunità di fare qualcosa di più granulare:limitare le autorizzazioni SELECT/UPDATE/DELETE dell'utente a un sottoinsieme del set di dati nella tabella (controllo dell'accesso a grana fine).
Fig. 1. StaffScope e tabelle del personale
Ruoli e utenti del database
Il Listato 2 mostra gli utenti ei ruoli che dobbiamo creare per procedere con la nostra soluzione. L'idea è che esiste una relazione tra lo staff memorizzato nelle tabelle utente Staff e StaffScope e le entità database che questo staff utilizzerà alla fine per accedere ai dati. Osservare la colonna in Fig. 1 chiamata DBUserID . Questa colonna viene compilata utilizzando la funzione DATABASE_PRINCIPAL_ID (vedi Listato 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;
Finora in sintesi quello che abbiamo fatto è:
- Crea/identifica le tabelle che dobbiamo proteggere
- Crea tabelle che indichino i criteri che utilizzeremo per limitare l'accesso ai dati a livello di riga (Ambito)
- Creazione di ruoli e utenti del database a cui applicheremo le restrizioni
- Accesso limitato alle tabelle principali ("Sicurezza a livello di tabella") utilizzando ruoli e autorizzazioni
Funzione di previsione e politica di sicurezza
Finora abbiamo ciò che potremmo chiamare sicurezza a livello di tabella implementata utilizzando ruoli e autorizzazioni. Ora vogliamo andare più a fondo. Vogliamo che due principali che dispongono dei privilegi SELECT su una tabella possano eseguire query sulla tabella ma visualizzare set di dati diversi in base alle condizioni che abbiamo impostato. Listato 3 ci mostra come riusciamo a raggiungere questo obiettivo.
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 funzione predicato definisce le condizioni che devono essere soddisfatte affinché un principal possa visualizzare un sottoinsieme di dati interessanti. In questa funzione, ci sono tre condizioni:
- L'utente del database dello Staff è un membro del Nazionale ruolo e AffiliateID corrisponde a quello del personale O
- L'utente del database dello Staff è un membro del Regionale ruolo e AffiliateID corrisponde all'elenco di AffiliateID appartiene alla regione dell'Africa occidentale O
- L'utente del database di Staff è un membro del Globale
Ciò implica che un membro del Globale il ruolo vede tutti i dati semplicemente perché appartiene a quel ruolo. Tuttavia, i membri degli altri due ruoli devono soddisfare criteri aggiuntivi che confinano con gli AffiliateID .
Affinché la funzione sia utile, applicalo alle tabelle come predicati FILTER o BLOCK. I predicati FILTER limitano ciò che il principale può vedere mentre i predicati BLOCK assicurano che il principale non possa manipolare dati al di fuori di quelli che gli vengono presentati dalle restrizioni definite nella funzione. Una politica di sicurezza è un contenitore in cui specifichiamo i predicati FILTER e BLOCK per tutte le tabelle che ci interessano. Dai un'occhiata al Listato 3 di nuovo.
Un aspetto molto interessante di questo approccio è la modularità. Possiamo applicare i predicati a tabelle aggiuntive nella politica di sicurezza senza influire sulle tabelle definite esistenti, possiamo aggiungere nuove entità database (Staff) creando utenti di database e concedendo loro i ruoli appropriati. Quando si verifica lo spostamento del personale, possiamo aggiornare le assegnazioni dei ruoli e così via.
Test dell'implementazione
Quindi, ora che abbiamo finito, possiamo impersonare i principali del database per determinare se abbiamo i risultati attesi usando il codice nel Listato 4. Prima di esaminarlo, vediamo i ruoli associati a ciascun personale e ai suoi affiliati nella Fig. 2.
Fig. 2. Elenco del personale
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';
Nella prima riga, interrogo i Clienti tabella come amministratore di sistema ma non ottengo RIGHE. Ciò significa che anche un amministratore non può ignorare gli effetti di RLS senza rappresentazione.
Fig. 4. SysAdmin non vede righe
Barbara ed Edward sono entrambi dirigenti e appartengono al National Scope ma lavorano in paesi diversi, quindi vedono i clienti associati alle rispettive affiliate. (Vedi i nomi del personale in Fig. 1).
Fig. 5. I dirigenti vedono le righe del proprio affiliato
John e Margaret sono Country e Group Manager. Appartengono alla Regionale e Globale Ambiti rispettivamente. John vede i dati per l'Africa occidentale, mentre Margaret vede i dati per tutte le regioni.
Fig. 6. I gestori vedono le righe della loro regione
I risultati sono gli stessi per tutte le altre tabelle alle quali è stata applicata la Security Policy. Osservalo senza autorizzazioni su Transazioni tabella, la sicurezza a livello di riga non ha alcun valore.
Fig. 7. Nessuna autorizzazione SELECT su Transazioni Tabella
Listing 5 – Permissions on Transactions Table grant select on dbo.Transactions to [National];
Fig. 8. Transazioni La tabella vista dai dirigenti
Conclusione
La sicurezza a livello di riga è un metodo potente per sfruttare la capacità di controllo degli accessi a grana fine di SQL Server. L'uso di questa funzionalità richiede l'esecuzione di SQL Server 2016 o versioni successive. Come suggerisce il nome, l'obiettivo è limitare l'accesso alle righe all'interno di una tabella utilizzando query complesse dopo aver curato la "sicurezza a livello di tabella". Gli scenari in cui questa capacità può essere applicata sono infiniti, quindi è molto utile per un'ampia gamma di ambienti. Fai bene a esplorare e vedere cosa può fare per te.
Riferimenti
Isakov, V. (2018). Esame Ref 70-764 Amministrazione di un'infrastruttura di database SQL . Educazione Pearson
Sicurezza a livello di riga