Waarom is beveiliging op rijniveau belangrijk?
Vóór SQL Server 2016 was beveiliging op tabelniveau het standaard laagste beveiligingsniveau voor een database. Met andere woorden, een gebruiker kan worden beperkt tot toegang tot een tabel als geheel. In sommige gevallen moeten gebruikers echter toegang hebben tot een tabel, maar niet tot specifieke rijen in de tabel. Voorafgaand aan SQL Server 2016 moesten hiervoor aangepaste opgeslagen procedures worden geschreven voor het bieden van dergelijke fijnmazige beveiliging. Dergelijke opgeslagen procedures zijn echter gevoelig voor SQL-injectie en andere beveiligingswaarschuwingen.
De beveiligingsfunctie op rijniveau van SQL Server gebruiken in de praktijk
SQL Server 2016 heeft een nieuwe beveiligingsfunctie op rijniveau geïntroduceerd waarmee gebruikers toegang hebben tot een tabel, maar die hen beperkt tot toegang tot specifieke rijen binnen die tabel. Laten we eens kijken hoe dit praktisch kan worden gebruikt.
Beschrijving
Er zijn vier stappen om beveiliging op rijniveau in SQL Server te implementeren.
- Verleen Select-machtigingen aan de gebruikers in de tabel waarop u beveiliging op rijniveau wilt implementeren.
- Vervolgens moet je een inline-tabelwaardefunctie schrijven die een filterpredikaat bevat. Voeg de filterlogica toe aan het filterpredikaat.
- Ten slotte moet u het filterpredikaat dat u in de tweede stap hebt gemaakt, binden aan een beveiligingsbeleid.
- Test de beveiligingsfunctie op rijniveau.
Voordat we de bovenstaande stappen uitvoeren, moeten we een dummy-database maken met enkele dummy-records. Voer hiervoor het volgende script uit:
DATABASE MAKEN UniversityGOUSE UniversityGOUSE UniversityCREATE TABEL Personen(Id INT PRIMARY KEY IDENTITY(1,1),Name VARCHAR (50),Rol VARCHAR (50))GOUSE UniversityINSERT INTO Persons VALUES ('Sally', 'Principal' )INSERT INTO Personen WAARDEN ('Edward', 'Student' )INVOEG IN Personen WAARDEN ('Jon', 'Student' )INVOEG IN Personen WAARDEN ('Scot', 'Student')INVOEG IN Personen WAARDEN ('Ben', 'Student' ) INVOEREN IN WAARDEN VAN PERSONEN ('Isabel', 'Leraar' )INVOEREN IN WAARDEN van personen ('David', 'Leraar' )INVOEREN IN WAARDEN van personen ('Laura', 'Leraar' )INVOEREN IN WAARDEN van personen ('Jean', 'Leraar' ')INSERT INTO Person VALUES ('Francis', 'Leraar' )
In het script creëren we een dummy-database "University". Vervolgens voeren we het script uit dat een tabel met de naam "Personen" maakt. Als je naar het tabelontwerp kijkt, kun je zien dat het drie kolommen Id, Name en Role bevat. De Id-kolom is de primaire sleutelkolom met IDENTITY-beperking. De kolom Naam bevat de naam van de persoon en de kolom Rol bevat de rol van de persoon. Ten slotte hebben we 10 records in de tabel Personen ingevoegd. De tafel heeft 1 directeur, 4 docenten en 5 studenten.
Laten we een eenvoudige SELECT-instructie uitvoeren om records in de tabel te zien:
Gebruik UniversitySELECT * FROM Persons
Het resultaat ziet er als volgt uit:
We willen dat de gebruiker met de naam Principal toegang heeft tot alle rijen in de tabel Personen. Evenzo zou een docent alleen toegang moeten hebben tot de docentenrecords, terwijl studenten alleen toegang moeten hebben tot studentrecords. Dit is een klassiek geval van beveiliging op rijniveau.
Om de beveiliging op rijniveau te implementeren, volgen we de stappen die we eerder hebben besproken.
Stap 1:Verleen geselecteerde machtigingen aan gebruikers op de tafel
Laten we drie gebruikers maken met de rollen Principal, Docent en Student en hen SELECT-toegang verlenen tot deze gebruikers in de tabel Personen. Voer hiervoor het volgende script uit:
GEBRUIKER MAKEN Directeur ZONDER LOGIN;GOCREATE GEBRUIKER Docent ZONDER LOGIN;GOCREATE GEBRUIKER Student ZONDER LOGIN;GOUse University GRANT SELECTEREN OP Personen NAAR Opdrachtgever;GOGRANT SELECTEREN OP Personen NAAR Docent;GOGRANT SELECTEREN OP Personen NAAR student;GO
Stap 2:Filterpredicaat maken
Nadat de gebruikers toestemming hebben gekregen, is de volgende stap het maken van een filterpredikaat.
Het volgende script doet dat:
Gebruik UniversityGOCREATE-FUNCTIE dbo.fn_SP_Person(@Role AS sysname) RETURNS TABLEMET SCHEMABINDINGAS RETURN SELECT 1 AS fn_SP_Person_output -- Predikaatlogica WHERE @Role =USER_NAME() OR USER_NAME()' ='Principal>';Het filterpredikaat wordt gemaakt binnen een inline tabelwaardefunctie en neemt de rol van de gebruiker als parameter aan. Het retourneert die records waarbij de rolwaarde die als parameter is doorgegeven, overeenkomt met de rolwaarde in de kolom Rol. Of als de gebruikersrol 'Principaal' is, worden alle rollen geretourneerd. Als u naar het predikaatfilter kijkt, vindt u niet de tabelnaam waarvoor we het filter maken. Het filterpredikaat is verbonden met de tabel via het beveiligingsbeleid dat we in de volgende stap zullen zien.
Stap 3:Een beveiligingsbeleid maken
Voer het volgende script uit om een beveiligingsbeleid te maken voor het filterpredikaat dat we in de laatste stap hebben gemaakt:
Gebruik UniversityGoCREATE BEVEILIGINGSBELEID RoleFilterADD FILTER PREDICATE dbo.fn_SP_Person(Rol)ON dbo.PersonsWITH (STATE =ON);GOIn het beveiligingsbeleid hebben we eenvoudig het filterpredikaat toegevoegd dat we hebben gemaakt aan de tabel Personen. Om het beleid in te schakelen, moet de vlag "STATE" worden ingesteld op AAN.
Stap 4:Beveiliging op rijniveau testen
We hebben alle stappen uitgevoerd die nodig zijn om beveiliging op rijniveau af te dwingen in de tabel Personen van de universiteitsdatabase. Laten we eerst proberen om via de standaardgebruiker toegang te krijgen tot de records in de tabel Personen. Voer het volgende script uit:
Gebruik UniversitySELECT * FROM Persons;GOU zult niets zien in de uitvoer, aangezien de standaardgebruiker geen toegang heeft tot de tabel Personen.
Laten we overschakelen naar de Student-gebruiker die we eerder hebben gemaakt en proberen records uit de tabel Personen te SELECTEREN:
EXECUTE AS USER ='Student';Gebruik UniversitySELECT * FROM Persons; -- Alleen studentenrecordsREVERT;GOIn bovenstaand script schakelen we over naar de ‘Student’-gebruiker, selecteren records uit de tabel Personen en keren terug naar de standaardgebruiker. De uitvoer ziet er als volgt uit:
U kunt zien dat vanwege de beveiliging op rijniveau alleen records worden weergegeven waarin de kolom Rol de waarde Student heeft.
Evenzo heeft de gebruiker Docent alleen toegang tot records waarin de kolom Rol de waarde Docent heeft. Voer het volgende script uit om dit te verifiëren:
EXECUTE AS USER ='Leraar';Gebruik UniversitySELECT * FROM Persons; -- Alle records REVERT;GOIn de uitvoer ziet u de volgende records:
Ten slotte hebben we in ons filterpredikaat de logica geïmplementeerd dat de gebruiker-Principal toegang heeft tot alle records. Laten we dit verifiëren door de volgende query uit te voeren:
EXECUTE AS USER ='Principal';Gebruik UniversitySELECT * FROM Persons; -- Alle records REVERT;GOIn de uitvoer ziet u alle records zoals hieronder weergegeven:
Conclusie
De beveiligingsfunctie op rijniveau is uiterst handig wanneer u wilt dat gebruikers gedetailleerde toegang hebben tot specifieke gegevens. De beveiligingsfunctie op rijniveau omvat echter een inline tabelwaardefunctie, waardoor u een prestatiehit kunt oplopen.
Als vuistregel geldt dat als u van plan bent een eenvoudige WHERE-clausule in de predikaatfunctie te gebruiken, uw prestaties niet worden beïnvloed. Aan de andere kant moeten complexe join-instructies met opzoektabellen worden vermeden wanneer u beveiliging op rijniveau hebt geïmplementeerd.