@DynamicDataMasking: примеры (SQL)

Динамическое маскирование данных в MS SQL Server
Раздел: Функции работы с динамическими масками данных
@DynamicDataMasking

Функция Dynamic Data Masking в MS SQL Server

Dynamic Data Masking (DDM), или динамическое маскирование данных, является функцией безопасности на уровне базы данных в MS SQL Server, начиная с версии 2016. Это не функция T-SQL в классическом понимании, а свойство столбца таблицы. DDM ограничивает доступ к конфиденциальным данным, маскируя их для непривилегированных пользователей, не изменяя сами данные на уровне хранилища. Маскирование применяется на этапе выполнения запроса.

Использование актуально для сценариев, где необходимо скрыть часть данных (например, ПИН-коды, номера телефонов, электронные адреса) от пользователей приложений или аналитиков, но при этом сохранить возможность работы с форматом данных для систем интеграции или тестирования.

Функция не имеет аргументов в виде параметров функции. Маскирование определяется при создании или изменении таблицы с помощью предложения MASKED WITH в ALTER TABLE или CREATE TABLE. Основные типы масок:

  • FUNCTION = 'default()': Полная маска для строк (XXXX), чисел (0), дат (01.01.1900).
  • FUNCTION = 'email()': Показывает первую букву, заменяет остальную часть домена на XXX.com (aXXX@XXX.com).
  • FUNCTION = 'partial(prefix, padding, suffix)': Показывает указанные префикс и суффикс, заменяя середину заданным символом.
  • FUNCTION = 'random(start, end)': Заменяет числовое значение случайным числом в заданном диапазоне.

Возвращаемым значением для пользователя без прав UNMASK является маскированная версия данных. Для привилегированных пользователей или в самом хранилище данные остаются исходными.

Краткие примеры использования

Создание таблицы с разными типами масок:

CREATE TABLE dbo.ClientData (
ID INT IDENTITY PRIMARY KEY,
FullName NVARCHAR(100) MASKED WITH (FUNCTION = 'default()'),
Email NVARCHAR(100) MASKED WITH (FUNCTION = 'email()'),
PhoneNumber NVARCHAR(20) MASKED WITH (FUNCTION = 'partial(3,"******",2)'),
CreditCardLastFour CHAR(4) MASKED WITH (FUNCTION = 'partial(0,"****",4)'),
SecretNumber INT MASKED WITH (FUNCTION = 'random(100, 999)')
);

INSERT INTO dbo.ClientData (FullName, Email, PhoneNumber, CreditCardLastFour, SecretNumber)
VALUES ('Иванов Петр', 'petr@example.com', '+79161234567', '1234', 42);

-- Создание пользователя без прав UNMASK
CREATE USER TestUser WITHOUT LOGIN;
GRANT SELECT ON dbo.ClientData TO TestUser;

EXECUTE AS USER = 'TestUser';
SELECT * FROM dbo.ClientData;
REVERT;
ID | FullName | Email            | PhoneNumber  | CreditCardLastFour | SecretNumber
---+----------+------------------+--------------+--------------------+-------------
1 | XXXX | pXXX@XXX.com | +79******67 | ****1234 | 753

Добавление маски к существующему столбцу:

ALTER TABLE dbo.ClientData
ALTER COLUMN FullName ADD MASKED WITH (FUNCTION = 'partial(2, "*", 1)');

Похожие технологии в MS SQL Server

Статическое маскирование данных (Static Data Masking), представленное в SQL Server 2019, необратимо заменяет данные в копии базы, что подходит для создания тестовых сред. В отличие от DDM, исходные данные изменяются.

Always Encrypted обеспечивает более высокий уровень безопасности, шифруя данные как на стороне клиента, так и на сервере. Даже администраторы базы данных не могут видеть исходные значения. DDM проще в реализации, но менее безопасен, так как данные на сервере не шифруются.

Шифрование на уровне столбцов (Column-level Encryption) с использованием симметричных ключей. Требует явного вызова функций шифрования/расшифровки и управления ключами. DDM проще для прозрачного скрытия данных от определенных ролей пользователей.

Типичные ошибки

Попытка обновить данные через маскированное представление. Пользователь без прав UNMASK не сможет корректно обновить маскированный столбец, если маскирование не детерминировано (например, random()).

EXECUTE AS USER = 'TestUser';
UPDATE dbo.ClientData SET PhoneNumber = '+79165555555' WHERE ID = 1;
-- Значение будет обновлено, но для пользователя оно по-прежнему будет отображаться замаскированным.

Неверное понимание области действия. Маскирование не влияет на данные при экспорте, если у пользователя есть право SELECT. Данные экспортируются в исходном виде. Для защиты необходимы отдельные права.

Использование с индексированием. Маскирование может повлиять на производительность запросов с предикатами WHERE по замаскированным столбцам, так как преобразование происходит после доступа к индексу.

-- Для пользователя без UNMASK этот запрос не найдет запись, даже если email 'petr@example.com' существует.
EXECUTE AS USER = 'TestUser';
SELECT * FROM dbo.ClientData WHERE Email = 'petr@example.com';
REVERT;

Изменения в последних версиях

Начиная с SQL Server 2022, появилась возможность использовать маскирование в сочетании с другими функциями безопасности, такими как Always Encrypted с безопасными анклавами. Это позволяет выполнять вычисления над зашифрованными данными, сохраняя при этом маскирование для непривилегированных пользователей.

Также были улучшены производительность и интеграция с системой управления правами. Существенных изменений в синтаксисе определения масок с момента введения (SQL Server 2016) не было.

Расширенные примеры

Комбинирование маскирования с другими объектами базы данных. Создание представления, которое дополнительно фильтрует замаскированные данные:

Пример sql
CREATE VIEW vw_SafeClientData 
AS
SELECT ID,
FullName,
Email,
PhoneNumber
FROM dbo.ClientData
WHERE IsActive = 1;

GRANT SELECT ON vw_SafeClientData TO TestUser;

Использование в динамическом SQL. Маскирование сохраняется, даже если запрос формируется динамически.

Пример sql
EXECUTE AS USER = 'TestUser';
DECLARE @sql NVARCHAR(MAX) = 'SELECT Email FROM dbo.ClientData WHERE ID = 1';
EXEC sp_executesql @sql;
REVERT;
-- Результат будет замаскирован.

Работа с JOIN. При соединении таблиц маскирование действует только для столбцов, для которых оно определено.

Пример sql
CREATE TABLE dbo.Orders (OrderID INT, ClientID INT, Amount MONEY);
INSERT INTO dbo.Orders VALUES (100, 1, 5000);

EXECUTE AS USER = 'TestUser';
SELECT o.OrderID, c.Email, o.Amount
FROM dbo.Orders o
JOIN dbo.ClientData c ON o.ClientID = c.ID;
REVERT;
-- В результатах Email будет замаскирован, а Amount (не маскирован) отобразится как есть.

Условное маскирование на основе роли пользователя (через предикаты безопасности) напрямую не поддерживается DDM. Для этого требуется использовать Row-Level Security (RLS) вместе с представлениями, которые применяют функции маскирования условно.

Аналоги в других СУБД

Oracle: Функция Data Redaction (начиная с 12c). Обеспечивает сходную с DDM функциональность, но с более тонкой настройкой контекста (например, через условия WHERE).

-- Oracle
BEGIN DBMS_REDACT.ADD_POLICY(
object_name => 'EMPLOYEES',
column_name => 'SALARY',
policy_name => 'redact_salary',
function_type => DBMS_REDACT.PARTIAL,
function_parameters => '1,1,4'
); END;

PostgreSQL: Нет встроенного аналога. Реализуется через представления (VIEWS) с функциями маскирования или расширения, например, pg_masking.

-- PostgreSQL через VIEW
CREATE VIEW masked_customer AS
SELECT id,
regexp_replace(email, '(.)(.*)@', '\1***@') as email
FROM customer;

MySQL: Встроенного аналога нет. Используются представления или функции для маскирования при выборке (например, CONCAT, SUBSTRING).

-- MySQL
SELECT name, CONCAT(LEFT(email, 1), '***@', SUBSTRING_INDEX(email, '@', -1)) AS masked_email
FROM users;

SQLite: Отсутствует. Требуется ручное преобразование в запросах.

MS SQL @DynamicDataMasking function comments

En
@DynamicDataMasking Not a function, but a feature. Functions for managing are typically procedures (e.g., sp_add_data_masking).