Реализация безопасности на уровне строк

Завершено

Безопасность на уровне строк (RLS) не использует шифрование и работает на уровне базы данных для ограничения доступа к таблице с помощью политики безопасности на основе членства в группах или контекста авторизации. Это функционально эквивалентно предложению WHERE.

Политика безопасности вызывает встроенную функцию с табличным значением для защиты доступа к строкам таблицы.

В зависимости от атрибута, назначенного пользователю, предикат определяет права доступа этого пользователя к соответствующей информации. При выполнении запроса к таблице политика безопасности применяет функцию предиката. В зависимости от бизнес-требований безопасность на уровне строк может быть очень простой (например, WHERE CustomerId = 29) или настолько сложной, насколько потребуется.

Безопасность на уровне строк поддерживает следующие два типа политик безопасности

  • Фильтрация предикатов — ограничение любого доступа к данным, который нарушает предикат.

    Открыть Определение
    SELECT Отфильтрованные строки нельзя просматривать.
    UPDATE Отфильтрованные строки нельзя обновлять.
    DELETE Отфильтрованные строки нельзя удалять.
    INSERT Неприменимо.
  • Блокировка предикатов — ограничение изменений данных, которые нарушают предикат.

    Открыть Определение
    ПОСЛЕ ВСТАВКИ Запрещает пользователям вставлять строки со значениями, которые нарушают предикат.
    ПОСЛЕ ОБНОВЛЕНИЯ Запрещает пользователям сохранять в существующие строки новые значения, которые нарушают предикат.
    ПЕРЕД ОБНОВЛЕНИЕМ Запрещает пользователям обновлять строки, которые в настоящий момент нарушают предикат.
    ПЕРЕД УДАЛЕНИЕМ Блокирует операции удаления, если для строки нарушается предикат.

Так как управление доступом настраивается и применяется на уровне базы данных, изменения в приложении будут минимальными или не потребуются вовсе. Кроме того, пользователи смогут напрямую обращаться к таблицам и запрашивать данные удобным для них способом.

Для реализации безопасности на уровне строк нужно выполнить три основных шага.

  1. Создайте пользователей или группы, по которым будет определяться доступ.
  2. Создайте встроенную функцию, возвращающую табличное значение, которая фильтрует результаты на основе заданного предиката.
  3. Создайте политику безопасности для таблицы, назначив созданную ранее функцию.

В следующих командах T-SQL показано, как использовать RLS в сценарии разделения доступа пользователей по клиенту:

-- Create supporting objects for this example
CREATE TABLE [Sales] (SalesID INT, 
    ProductID INT, 
    TenantName NVARCHAR(10), 
    OrderQtd INT, 
    UnitPrice MONEY)
GO

INSERT INTO [Sales]  VALUES (1, 3, 'Tenant1', 5, 10.00);
INSERT INTO [Sales]  VALUES (2, 4, 'Tenant1', 2, 57.00);
INSERT INTO [Sales]  VALUES (3, 7, 'Tenant1', 4, 23.00);
INSERT INTO [Sales]  VALUES (4, 2, 'Tenant2', 2, 91.00);
INSERT INTO [Sales]  VALUES (5, 9, 'Tenant3', 5, 80.00);
INSERT INTO [Sales]  VALUES (6, 1, 'Tenant3', 5, 35.00);
INSERT INTO [Sales]  VALUES (7, 3, 'Tenant4', 8, 11.00);

-- View all the rows in the table  
SELECT * FROM Sales;

Затем создайте пользователей и предоставьте им доступ к таблице Sales. В нашем примере каждый пользователь обозначает определенный арендатор. Пользователь TenantAdmin имеет доступ к просмотру данных из любого арендатора.

CREATE USER [TenantAdmin] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant1] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant2] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant3] WITH PASSWORD = '<strong password>'
GO
CREATE USER [Tenant4] WITH PASSWORD = '<strong password>'
GO

GRANT SELECT ON [Sales] TO [TenantAdmin]
GO
GRANT SELECT ON [Sales] TO [Tenant1]
GO
GRANT SELECT ON [Sales] TO [Tenant2]
GO
GRANT SELECT ON [Sales] TO [Tenant3]
GO
GRANT SELECT ON [Sales] TO [Tenant4]
GO

Затем мы создадим новую схему, встроенную табличную функцию и предоставим пользователю доступ к новой функции. Предикат WHERE @TenantName = USER_NAME() OR USER_NAME() = 'TenantAdmin' проверяет, соответствует ли имя пользователя, выполняющего запрос, значениям в столбце TenantName.

CREATE SCHEMA sec;  
GO  

--Create the filter predicate

CREATE FUNCTION sec.tvf_SecurityPredicatebyTenant(@TenantName AS NVARCHAR(10))  
    RETURNS TABLE  
WITH SCHEMABINDING  
AS  
    RETURN	SELECT 1 AS result
			WHERE @TenantName = USER_NAME() OR USER_NAME() = 'TenantAdmin';  
GO

--Grant users access to inline table-valued function

GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [TenantAdmin]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant1]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant2]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant3]
GO
GRANT SELECT ON sec.tvf_SecurityPredicatebyTenant TO [Tenant4]
GO

--Create security policy and add the filter predicate
CREATE SECURITY POLICY sec.SalesPolicy  
ADD FILTER PREDICATE sec.tvf_SecurityPredicatebyTenant(TenantName) ON [dbo].[Sales]
WITH (STATE = ON);  
GO

Теперь мы готовы проверить настроенный доступ.

EXECUTE AS USER = 'TenantAdmin';  
SELECT * FROM dbo.Sales;
REVERT;  
  
EXECUTE AS USER = 'Tenant1';  
SELECT * FROM dbo.Sales;
REVERT;  
  
EXECUTE AS USER = 'Tenant2';  
SELECT * FROM dbo.Sales;
REVERT;

EXECUTE AS USER = 'Tenant3';  
SELECT * FROM dbo.Sales;
REVERT;

EXECUTE AS USER = 'Tenant4';  
SELECT * FROM dbo.Sales;
REVERT;

Пользователь TenantAdmin должен видеть все строки. Пользователи Tenant1, Tenant2, Tenant3 и Tenant4 должны видеть только свои строки.

При изменении политики WITH (STATE = OFF);безопасности обратите внимание, что пользователи видят все строки.

Снимок экрана: команды T-SQL для изменения политики безопасности.

Примечание.

Существует риск утечки информации, если злоумышленник записывает запрос с специально созданным WHERE предложением и, например, ошибкой деления на ноль, чтобы принудительно заставить исключение, если WHERE условие имеет значение true. Такой метод называется атакой по сторонним каналам. Рекомендуется ограничить возможность пользователей выполнять незапланированные запросы при использовании безопасности на уровне строк.

Вариант использования

Безопасность на уровне строк идеально подходит для многих сценариев, примеры которых перечислены ниже.

  • Вам необходимо изолировать доступ на уровне строк по отделам организации.
  • Вам нужно предоставить доступ клиентам только к тем данным, которые относятся к соответствующей компании.
  • Вам необходимо ограничить доступ для обеспечения соответствия требованиям.

Лучшие практики

Ниже приведены несколько рекомендаций, которые следует учитывать при реализации безопасности на уровне строк.

  • Создайте отдельную схему для функций предиката и политик безопасности.
  • Избегайте преобразований типов в функциях предиката.
  • Избегайте использования чрезмерных соединений таблиц и рекурсии в функциях предиката.