sql >> Base de Datos >  >> RDS >> Sqlserver

Introducción a la seguridad de nivel de fila en SQL Server

¿Por qué es importante la seguridad a nivel de fila?

Antes de SQL Server 2016, la seguridad a nivel de tabla era el nivel de seguridad más bajo predeterminado para una base de datos. En otras palabras, se podría restringir el acceso de un usuario a una tabla como un todo. Sin embargo, en algunos casos necesitamos que los usuarios tengan acceso a una tabla, pero no a filas específicas dentro de la tabla. Antes de SQL Server 2016, esto requería que se escribieran procedimientos almacenados personalizados para proporcionar una seguridad tan detallada. Sin embargo, dichos procedimientos almacenados son propensos a la inyección SQL y otras advertencias de seguridad.

Uso de la función de seguridad de nivel de fila de SQL Server en la práctica

SQL Server 2016 introdujo una nueva característica de seguridad a nivel de fila que permite a los usuarios tener acceso a una tabla pero les restringe el acceso a filas específicas dentro de esa tabla. Echemos un vistazo a cómo se puede usar esto en la práctica.

Descripción

Hay cuatro pasos para implementar la seguridad de nivel de fila en SQL Server.

  1. Otorgue permisos de selección a los usuarios de la tabla en la que desea implementar la seguridad de nivel de fila.
  2. A continuación, debe escribir una función de valor de tabla en línea que contenga un predicado de filtro. Agregue la lógica de filtro al predicado de filtro.
  3. Finalmente, debe vincular el predicado de filtro que creó en el segundo paso a una política de seguridad.
  4. Pruebe la función de seguridad a nivel de fila.

Antes de realizar los pasos anteriores, necesitamos crear una base de datos ficticia con algunos registros ficticios. Ejecute el siguiente script para hacerlo:

CREATE DATABASE University
GO

USE University
GO

USE University
CREATE TABLE Persons
(
Id INT PRIMARY KEY IDENTITY(1,1),
Name VARCHAR (50),
Role VARCHAR (50)
)
GO

USE University
INSERT INTO Persons VALUES ('Sally', 'Principal' )
INSERT INTO Persons VALUES ('Edward', 'Student' )
INSERT INTO Persons VALUES ('Jon', 'Student' )
INSERT INTO Persons VALUES ('Scot', 'Student')
INSERT INTO Persons VALUES ('Ben', 'Student' )
INSERT INTO Persons VALUES ('Isabel', 'Teacher' )
INSERT INTO Persons VALUES ('David', 'Teacher' )
INSERT INTO Persons VALUES ('Laura', 'Teacher' )
INSERT INTO Persons VALUES ('Jean', 'Teacher')
INSERT INTO Persons VALUES ('Francis', 'Teacher' )

En el script, creamos una base de datos ficticia "Universidad". A continuación, ejecutamos el script que crea una tabla llamada "Personas". Si observa el diseño de la tabla, puede ver que contiene tres columnas Id, Name y Role. La columna Id es la columna de clave principal con restricción de IDENTIDAD. La columna Nombre contiene el nombre de la persona y la columna Función contiene la función de la persona. Finalmente, insertamos 10 registros en la tabla Personas. La mesa tiene 1 director, 4 profesores y 5 alumnos.

Ejecutemos una instrucción SELECT simple para ver los registros en la tabla:

Use University
SELECT * FROM Persons

El resultado se ve así:

Queremos que el usuario llamado Principal tenga acceso a todas las filas de la tabla Personas. De manera similar, un Profesor debe tener acceso solo a los registros del Profesor, mientras que los Estudiantes deben tener acceso solo a los registros de los Estudiantes. Este es un caso clásico de seguridad a nivel de fila.

Para implementar la seguridad de nivel de fila, seguiremos los pasos que discutimos anteriormente.

Paso 1:otorgar permisos de selección a los usuarios en la tabla

Vamos a crear tres usuarios con roles Principal, Profesor y Estudiante y otorgarles acceso SELECCIONAR a estos usuarios en la tabla Personas. Ejecute el siguiente script para hacerlo:

CREATE USER Principal WITHOUT LOGIN;
GO
CREATE USER Teacher WITHOUT LOGIN;
GO
CREATE USER Student WITHOUT LOGIN;
GO

Use University
GRANT SELECT ON Persons TO Principal;
GO
GRANT SELECT ON Persons TO Teacher;
GO
GRANT SELECT ON Persons TO Student;
GO

Paso 2:Crear predicado de filtro

Una vez que los usuarios hayan obtenido los permisos, el siguiente paso es crear un predicado de filtro.

El siguiente script hace eso:

Use University
GO
CREATE FUNCTION dbo.fn_SP_Person(@Role AS sysname)
    RETURNS TABLE
WITH SCHEMABINDING
AS
    RETURN SELECT 1 AS fn_SP_Person_output
    -- Predicate logic
    WHERE @Role = USER_NAME()
    OR USER_NAME() = 'Principal';
GO

El predicado de filtro se crea dentro de una función con valores de tabla en línea y toma el rol del usuario como parámetro. Devuelve aquellos registros en los que el valor de Rol pasado como parámetro coincide con el valor de rol en la columna Rol. O si el rol de usuario es 'Principal', se devuelven todos los roles. Si observa el filtro de predicado, no encontrará el nombre de la tabla para la que estamos creando el filtro. El predicado de filtro está conectado a la tabla a través de la política de seguridad que veremos en el siguiente paso.

Paso 3:Creación de una política de seguridad

Ejecute el siguiente script para crear una política de seguridad para el predicado de filtro que creamos en el último paso:

Use University
Go
CREATE SECURITY POLICY RoleFilter
ADD FILTER PREDICATE dbo.fn_SP_Person(Role)
ON dbo.Persons
WITH (STATE = ON);
GO

En la política de Seguridad, simplemente agregamos el predicado de filtro que creamos a la tabla Personas. Para habilitar la política, el indicador "ESTADO" debe estar activado.

Paso 4:Probar la seguridad a nivel de fila

Realizamos todos los pasos necesarios para hacer cumplir la seguridad a nivel de fila en la tabla Personas de la base de datos de la Universidad. Primero intentemos acceder a los registros en la tabla Personas a través del usuario predeterminado. Ejecute el siguiente script:

Use University
SELECT * FROM Persons;
GO

No verá nada en la salida ya que el usuario predeterminado no puede acceder a la tabla Personas.

Pasemos al usuario Estudiante que creamos anteriormente e intentemos SELECCIONAR registros de la tabla Personas:

EXECUTE AS USER = 'Student';
Use University
SELECT * FROM Persons; -- Student Records Only
REVERT;
GO

En el script anterior, cambiamos al usuario 'Estudiante', seleccionamos registros de la tabla Personas y volvemos al usuario predeterminado. La salida se ve así:

Puede ver que, debido a la seguridad a nivel de fila, solo se muestran los registros en los que la columna Rol tiene un valor de Estudiante.

De manera similar, el usuario Profesor solo tendrá acceso a los registros donde la columna Rol tenga un valor de Profesor. Ejecute el siguiente script para verificar esto:

EXECUTE AS USER = 'Teacher';
Use University
SELECT * FROM Persons; -- All Records
REVERT;
GO

En la salida, obtendrá los siguientes registros:

Finalmente, en nuestro predicado de filtro, implementamos la lógica de que el usuario Principal puede acceder a todos los registros. Verifiquemos esto ejecutando la siguiente consulta:

EXECUTE AS USER = 'Principal';
Use University
SELECT * FROM Persons; -- All Records
REVERT;
GO

En la salida, verá todos los registros como se muestra a continuación:

Conclusión

La función de seguridad de nivel de fila es extremadamente útil cuando desea que los usuarios tengan acceso detallado a datos específicos. Sin embargo, la función de seguridad de nivel de fila implica una función de valores de tabla en línea, lo que puede hacer que se vea afectado el rendimiento.

Como regla general, si planea usar una cláusula WHERE simple en la función de predicado, su rendimiento no debería verse afectado. Por otro lado, las declaraciones de combinación complejas que involucran tablas de búsqueda deben evitarse cuando ha implementado seguridad a nivel de fila.