La Sicurezza Granulare di SQL Server 

Datamaze
19.06.24 04:20 PM Comment(s)

La sicurezza dei dati è un pilastro cruciale nell'amministrazione dei database, e SQL Server si distingue per le sue capacità avanzate di proteggere informazioni sensibili. Con il continuo aggiornamento e miglioramento della piattaforma, SQL Server ha integrato meccanismi di sicurezza sempre più raffinati e granulari. Tali miglioramenti non solo rispondono alle crescenti minacce informatiche ma offrono anche una flessibilità senza precedenti nella gestione delle autorizzazioni. 


L'approccio granulare alla sicurezza in SQL Server permette agli amministratori di definire permessi specifici a livelli estremamente dettagliati. Questo significa che le autorizzazioni possono essere impostate non solo a livello di tabelle o database interi ma possono arrivare fino al dettaglio di singole colonne e righe. Come vedremo nel caso studio, è possibile configurare permessi che limitano l'accesso a determinate informazioni in base al ruolo o al contesto di lavoro dell'utente, assicurando che ciascuno possa accedere solo ai dati necessari per le proprie funzioni specifiche. Questo modello di sicurezza dettagliato è particolarmente vantaggioso in ambienti con elevati standard di compliance e sicurezza, dove la minima esposizione di dati sensibili può comportare rischi significativi. L'implementazione di politiche di sicurezza a livello di riga (Row-Level Security, RLS), la mascheratura dinamica dei dati (Dynamic Data Masking, DDM) e la creazione di viste per limitare la visibilità dei dati sensibili, sono esempi di come SQL Server permetta agli amministratori di mettere in pratica una sicurezza personalizzata e ad alta definizione.


Le recenti versioni di SQL Server hanno ulteriormente potenziato queste capacità introducendo nuovi ruoli e permessi specifici che facilitano la gestione degli accessi senza necessariamente concedere diritti amministrativi completi, riducendo così il rischio di accessi non autorizzati o abusi.

Diagramma dei permessi granulari di SQL Server e Azure SQL
Figura 1 – Diagramma dei permessi granulari di SQL Server e Azure SQL [Microsoft Comunity]

Caso studio

Immaginiamo una situazione in cui l’agenzia “RoadTrip” effettua noleggio di biciclette. L’agenzia utilizza un omonimo database per tenere traccia di diverse informazioni quali le date dei noleggi, le informazioni sui clienti, ecc. A tale database hanno accesso diversi reparti della stessa azienda, l’ufficio HR, l’ufficio amministrazione, gli addetti alle vendite e al magazzino, ecc. 

Il database è composto dalle tabelle come illustrate in Figura 2:
Struttura del database RoadTrip
Figura 2 – Struttura del database RoadTrip
                Supponiamo che l'ufficio HR debba avere accesso alle informazioni sui clienti e della persona  che ha stipulato il contratto di noleggio, ecc. In veste di amministratori del database, il modo più semplice per selezionare quali dati mettere a disposizione a quale ufficio, è mediante la creazione di almeno un profilo (login) per ciascun ufficio. Consideriamo ad esempio la tabella 
  • CustomerID: Identificativo unico per ogni cliente.
  • Title: Titolo del cliente (es. Mr., Ms.). 
  • FirstName: Nome del cliente.
  • MiddleName: Secondo nome del cliente (se presente).
  • LastName: Cognome del cliente.
  • SalesPerson: Dipendente responsabile delle vendite che ha seguito il cliente.
  • EmailAddress: Indirizzo email del cliente.
  • AddressType: Tipo di indirizzo (es. Main Office).
  • Phone: Numero di telefono del cliente.
  • Password: Hash della password del cliente.
  • ModifiedDate: Data dell'ultima modifica del record. 

Prima di procedere alla creazione vera e propria delle utenze, è necessario decidere quali dati  vogliamo mettere a disposizione di ciascun ufficio. Nello specifico, vogliamo che l'ufficio HR abbia accesso alle informazioni sui clienti, ma senza visualizzarne le informazioni relative alle password o al numero di telefono. In questo caso, utilizzeremo una vista per garantire che solo certe colonne siano visibili all’ufficio HR,aiutando così a proteggere i dati sensibili. Una vista in SQL Server (e più in generale in molti sistemi di gestione di basi di dati relazionali) è essenzialmente una tabella virtuale basata sul risultato di una query SQL. Non è una tabella fisica con dati propri; piuttosto, è come una finestra attraverso la quale si possono vedere i dati presenti in una o più tabelle sottostanti.
Tabella 1 – Tabella CustomerDetails del database RoadTrip
Tabella 1 – Tabella CustomerDetails del database RoadTrip

Creazione di una Vista per limitare l’accesso ai dati sensibili

La creazione di una vista può avvenire tramite interfaccia grafica (GUI) oppure tramite codice T-SQL. Nel nostro caso studio saranno illustrate entrambe le strade. 

Una volta connessi all’istanza, espandere il database, tasto destro su Views > New View…
Dalla finestra pop-up selezionare la tabella i cui dati devono essere presenti nella vista – vedi 
Figura 3. Dal designer della lista, selezionare i campi che si vogliono includere nella vista. Nel 
nostro caso necessitiamo che l’HR abbia visibilità su tutti i campi, fuorché i dati sensibili – vedi 
Figura 4. Salviamo quindi la lista con il nome di HR_CustomerDetails.
Scelta delle Tabelle da inserire nella Vista
Figura 3 – Scelta delle Tabelle da inserire nella Vista
Designer della Vista
Figura 4 – Designer della Vista
Di seguito il codice T-SQL per la creazione della vista: 
CREATE VIEW [SalesLT].[HR_CustomerDetails]
AS
SELECT Title
	,FirstName
	,MiddleName
	,LastName
	,SalesPerson
	,EmailAddress
	,ModifiedDate
FROM [RoadTrip].[SalesLT].[CustomersDetails];

Codice 1 – Codice T-SQL per la creazione della vista HR_CustomerDetails 

Nella Tabella 2 possiamo apprezzare come le colonne contenenti i dati sensibili siano state escluse dalla vista. Ora non resta che creare l’utenza HR_viewers per dare i permessi di visualizzazione della vista. 
Risultato ritornato dalla vista HR_CustomerDetails
Tabella 2 – Risultato ritornato dalla vista HR_CustomerDetails

Creazione di un Login e di uno User

Un login in SQL Server è un'identità utilizzata per accedere all'istanza del server. Un login rappresenta un individuo, un gruppo o un processo che richiede accesso al server. È importante distinguere un ‘login’ da uno ‘user’ in quanto il primo permette la sola autenticazione al livello dell’istanza SQL Server, mentre il secondo autorizza l’accesso ad uno specifico database. Esiste tuttavia una relazione stretta tra login e user: quando un login cerca di accedere a un database, SQL Server mappa quel login ad uno user del database. Se non esiste alcuna mappatura valida tra il login e uno user nel database, l'accesso al database sarà negato, anche se il login è valido a livello di server. Questo meccanismo è essenziale per avere un controllo fine e granulare sull'accesso e sulle operazioni che possono essere eseguite all'interno di ciascun database. 

Esistono diversi tipi di login che possono essere configurati in SQL Server, ciascuno con le proprie modalità di autenticazione e autorizzazione. Di seguito li inglobiamo in tre gruppi principali: 
  • Windows Login: utilizzano le credenziali di autenticazione di Windows, permettendo agli utenti e ai gruppi definiti nel dominio Windows di accedere a SQL Server. L'autenticazione avviene attraverso il controllo di sicurezza di Windows, il che significa che gli utenti non hanno bisogno di fornire ulteriori credenziali quando accedono all’istanza SQL Server. 
  • SQL Server Login: sono specifici per SQL Server e non dipendono da Windows. Gli utenti devono fornire un nome utente e una password specifici quando si connettono a SQLServer. Questo tipo di login è utile per gli utenti che non fanno parte dell'ambiente di rete Windows, come nel caso di accessi da applicazioni web o da sistemi non Windows. 
  • Azure Active Directory Login: in ambienti cloud o ibridi che utilizzano Azure SQL Database, SQL Server supporta l'autenticazione tramite Azure Active Directory (Azure AD). Questo permette l'integrazione con le politiche e i controlli di sicurezza di Azure, facilitando la gestione degli accessi e delle identità. 

Procediamo con la creazione del login HR_viewers: 
Sull’istanza esplodiamo Security > Logins > New Login… e selezionare dal menù User Mapping il database di nostro interesse – vedi Figura 5.
Creazione di un Login per il database RoadTrip
Figura 5 – Creazione di un Login per il database RoadTrip
USE [master]

CREATE LOGIN [HR_viewers]
	WITH PASSWORD = N’ * * *,DEFAULT_DATABASE = [RoadTrip];

USE [RoadTrip]

CREATE USER [HR_viewers]
FOR LOGIN [HR_viewers];

ALTER USER [HR_viewers]
	WITH DEFAULT_SCHEMA = [SalesLT];
GO


Codice 2 – Codice T-SQL per la creazione di un login e la mappatura dello user
Durante la creazione del login, SQL Server Management Studio crea automaticamente uno user mappato al login. Durante il mapping l’amministratore può assegnare uno o più ruoli predefiniti a un utente di database. Questi ruoli determinano i permessi che possono essere attribuiti all’utente e possono variare da ruoli di sola lettura a ruoli amministrativi completi. Alcuni dei ruoli più 
comuni includono: 
  • db_owner: completo controllo amministrativo su tutte le funzioni del database 
  • db_datareader: permesso di leggere tutte le tabelle e le viste del database.
  • db_datawriter: permesso di modificare dati aggiungendo, eliminando o modificando le righe nelle tabelle.
  • db_ddladmin: permesso di eseguire comandi DDL (Data Definition Language), come CREATE, ALTER, e DROP.
  • public: collegamento al database, senza nessun permesso 

Nel nostro caso specifico, lo user HR_viewer – collegato all’omonimo login – è mappato come ‘public’. Per permettere all’utente di visualizzare la vista che abbiamo creato nel paragrafo precedente, tasto destro sulla vista > Properties. Dalla finestra Search… ed immettiamo il nome dello user a cui vogliamo attribuire le grant.
Grant di visualizzazione a HR_viewers sulla vista HR_CustomerDetail
Figura 6 – Grant di visualizzazione a HR_viewers sulla vista HR_CustomerDetail
USE [RoadTrip]

GRANT SELECT
	ON [SalesLT].[HR_CustomerDetails]
	TO [HR_viewers];
Codice 3 – Codice T-SQL per la creazione di un login e la mappatura dello user

Limitare l’Accesso ai dati Filtrando per Riga

Consideriamo ora un caso simile in cui gli addetti all’ufficio vendite hanno l’esigienza di controllare quali noleggi sono stati effettuati in passato. In veste di amministratori vogliamo permettere a ciascun utente di visualizzare esclusivamente le proprie operazioni di noleggio senza mostrare quelle dei colleghi. Per tale richiesta non è sufficiente la creazione di una vista, è necessario introdurre una funzionalità di sicurezza di SQL Server che prende – intuitivamente – il nome di Row Level Security (RLS).

L'implementazione della Row-Level Security (RLS) in SQL Server è una tecnica potente per garantire che i dati sensibili siano accessibili solo agli utenti autorizzati, basandosi su criteri definiti a livello di riga. RLS permette di controllare l'accesso ai dati in modo dinamico e sicuro senza modificare le applicazioni esistenti. Poiché le politiche di sicurezza sono gestite direttamente nel database, gli sviluppatori non devono scrivere controlli di sicurezza personalizzati in ogni applicazione che effettua l’accesso ai dati. Questo centralizza la logica di controllo degli accessi e riduce la complessità e il potenziale di errori. Tuttavia questa tecnica può influire pesantemente sulle prestazioni del database, poiché aggiunge un ulteriore livello di verifica per ogni query eseguita. È importante valutare l'impatto sulle prestazioni e ottimizzare le query e le politiche di sicurezza dove possibile, soprattutto in tabelle molto popolose.

Nel nostro caso studio, implementiamo la RLS sull’addetto alle vendite jillian0, per il quale abbiamo creato un login seguendo i passaggi illustrati nel paragrafo Creazione di un Login e di uno User con grant di db_datareader sulla tabella CustomerDetails.

A questo punto creiamo una funzione di sicurezza con un unico parametro @SalesPerson, il quale è definito come la concatenazione tra il nome dell’azienda e il nome dell’utente: 
CREATE FUNCTION SalesLT.SalesFilter (@SalesPerson NVARCHAR(128))
RETURNS TABLE
	WITH SCHEMABINDING
AS
RETURN

SELECT 1 AS SalesResult
WHERE @SalesPerson = CONCAT (
		N'adventure-works\'
		,SUSER_NAME()
		);
Codice 4 – Codice T-SQL per la creazione della funzione di sicurezza SalesFilter
Creiamo ora una politica di sicurezza basata sulla funzione appena creata che chiameremo SalesPersonFilter:
CREATE SECURITY POLICY SalesLT.SalesPersonFilter ADD FILTER PREDICATE SalesLT.SalesFilter (SalesPerson) ON SalesLT.CustomerDetails;

Codice 5 – Codice T-SQL per la creazione della politica di sicurezza SalesPersonFilter

Con tale politica di sicurezza applicata, gli unici record della tabella CustomerDetails che jillian0 potrà visualizzare sono illustrati in Tabella 3.
Risultato di una select dei primi 15 record eseguita da jillian0 sulla tabella CustomerDetails
Tabella 3 – Risultato di una select dei primi 15 record eseguita da jillian0 sulla tabella CustomerDetails

Conclusione

In conclusione, l'approccio di SQL Server alla gestione della sicurezza e della visibilità dei dati mediante l'utilizzo di viste e Row-Level Security (RLS) offre una soluzione robusta e flessibile per proteggere le informazioni sensibili e garantire che gli accessi siano adeguatamente regolamentati. Attraverso l'uso delle viste, è possibile creare finestre personalizzate sui dati che limitano l'esposizione a informazioni non necessarie per specifici ruoli o dipartimenti, migliorando la sicurezza e la gestione dei dati senza compromettere la facilità d'uso. 

D'altra parte, RLS permette un controllo ancora più granulare, assicurando che gli utenti possano accedere solo ai dati che sono autorizzati a vedere, basato su criteri definiti che operano a livello di riga all'interno delle tabelle. Questa funzionalità è particolarmente utile in ambienti con requisiti di privacy rigorosi, dove la minimizzazione dell'accesso ai dati è critica. 

Queste tecnologie non solo aumentano la sicurezza dei dati, ma migliorano anche la conformità alle normative sulla privacy e riducono il rischio di perdite di dati. Tuttavia, la corretta implementazione di queste funzionalità richiede una comprensione chiara delle loro implicazioni e limitazioni, come la gestione delle prestazioni e la configurazione corretta delle politiche e delle funzioni di sicurezza.

di Matteo Ambrosini, pubblicato il 19 giugno 2024