17 Занятие 17: Безопасность / Анонимизация данных
Эта страница извлечена из официального PDF в нативный Markdown. Текст слайдов, код и комментарии сохранены в порядке чтения; исходные PDF и HTML остаются эталоном макета. HTML source: pgpro_17_anonymize.html Archive: PGPRO-handouts-16.zip Страниц PDF: 23
Page 1: Безопасность / Анонимизация данных
Авторские права
© Postgres Professional, 2023–2026 Авторы: Алексей Береснев, Илья Баштанов, Павел Толмачев, Игорь Гнатюк Фото: Олег Бартунов (монастырь Пху и пик Бхрикути, Непал)
Использование материалов курса
Некоммерческое использование материалов курса (презентации, демонстрации) разрешается без ограничений. Коммерческое использование возможно только с письменного разрешения компании Postgres Professional. Запрещается внесение изменений в материалы курса.
Обратная связь
Отзывы, замечания и предложения направляйте по адресу: edu@postgrespro.ru
Отказ от ответственности
Компания Postgres Professional не несет никакой ответственности за любые повреждения и убытки, включая потерю дохода, нанесенные прямым или непрямым, специальным или случайным использованием материалов курса. Компания Postgres Professional не предоставляет каких-либо гарантий на материалы курса. Материалы курса предоставляются на основе принципа «как есть» и компания Postgres Professional не обязана предоставлять сопровождение, поддержку, обновления, расширения и изменения.
Page 2: Темы
- Анонимизация
- Стратегии анонимизации
- Расширение pgpro_anonymizer
- Правила маскирования
- Метки безопасности
- Динамическое изменение данных
- Статическое изменение по правилам
- Безопасность
Page 3: Анонимизация
{#source-figure-003 caption=“Source slide page 3: Анонимизация”}
Статическое Динамическое изменение изменение
Комментарии преподавателя
Защитить данные от несанкционированного чтения с помощью разделения доступа между ролями и назначения привилегий не всегда возможно: иногда пользователю необходимо показать какую-то информацию.
Дополнительным средством защиты данных в таких случаях может стать анонимизация — сохранение конфиденциальности путем изменения исходных данных или их представления в измененном виде:
● Статическое изменение — сохранение анонимизированных данных и дальнейшее их предоставление в уже измененном виде.
Такой вариант, например, позволяет скрыть исходную информацию в копиях данных, предназначенных для аналитиков, разработчиков и тестировщиков.
● Динамическое изменение (маскирование) — исходные данные не изменяются, а анонимизация и представление в измененном виде выполняются «на лету», непосредственно при обращении к ним.
Такой вариант может применяться, например, для защиты данных от просмотра недоверенными пользователями в приложениях.
Изменения данных, выполняемые при анонимизации, требуют затрат процессорного времени, места в памяти и, возможно, увеличения числа операций ввода-вывода. Статическое изменение перезаписывает данные на диске и затраты на него единовременны. При динамическом маскировании ресурсы расходуются при каждом обращении.
Page 4: Стратегии анонимизации
Удаление
- Замена
- Искажение
- Рандомизация и подмена
- Псевдонимизация
- Обобщение
- Перестановка
- Пользовательские правила
Комментарии преподавателя
Для анонимизации данных могут использоваться разные стратегии:
● Удаление (сокрытие) полностью исключает доступ к данным.
● Замена — все значения заменяются одним. Возможна частичная замена, когда часть данных остается нетронутой.
● Искажение (отклонение) «сдвигает» даты и числовые значения.
● Рандомизация и подмена (фальсификация) заменяют конфиденциальные данные случайными, но правдоподобными значениями.
● Псевдонимизация защищает данные, скрывая их с помощью дополнительной информации, при этом данные остаются связаны с исходными. Примерами могут служить шифрование и хеширование.
● Обобщение заменяет данные диапазоном значений.
● Перестановка перемешивает значения в рамках столбца.
● Пользовательские правила предназначены для анонимизации данных в соответствии с особыми требованиями — например, при необходимости логически согласованных изменений в столбцах.
Выбор стратегии анонимизации зависит от типа данных и задач обеспечения конфиденциальности. Например, для имен и различных идентификаторов удобно использовать замену, рандомизацию или псевдонимизацию, а отклонение и обобщение подходят для чисел и значений даты-времени.
Page 5: pgpro_anonymizer
Инструменты внутри СУБД
- для статического и динамического изменения
- Набор функций
- для разных стратегий анонимизации
- Декларативные конструкции
Комментарии преподавателя
Расширение pgpro_anonymizer позволяет анонимизировать данные внутри экземпляра СУБД без использования внешних инструментов, что уменьшает риск утечки данных. Расширение поставляется в виде отдельного пакета pgpro-anonymizer-ent-16; за его основу был взят проект PostgreSQL Anonymizer.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#PGPRO-ANON YMIZER
С помощью инструментов расширения можно выполнять статическое и динамическое изменение данных и применять в них различные стратегии анонимизации. Для этого в составе расширения имеются функции, выполняющие изменения данных в соответствии с выбранной стратегией.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#MASKING-FUN CTIONS
Чтобы связать данные со стратегией анонимизации, используется декларативный подход: стратегия описывается с помощью DDL-команд.
Page 6: Статическое изменение с помощью функций
Для работы расширения требуется загрузить разделяемую библиотеку.
Будем работать с демобазой. Подключимся к ней как суперпользователь:
Создадим расширение:
Появилась одноименная схема, в которой расширение хранит свои объекты:
Создадим схему, в которой будем размещать анонимизированные данные:
Для удобства временно добавим эту схему в путь поиска:
Считаем, что нам необходимо создать небольшой набор данных для тестировщиков, в котором нужно скрыть имена и фамилии пассажиров и исказить даты и суммы бронирований. Создадим в схеме m_schema таблицы m_tickets и m_bookings, в которые скопируем часть данных из таблиц tickets и bookings схемы bookings:
Подменим в исходной таблице имя и фамилию пассажиров. В состав расширения входит набор функций для подмены и набор функций, генерирующих случайные значения:
Page 7: Page 7
Функции подмены случайным образом выбирают значения из таблиц-словарей, также расположенных в схеме anon:
Функция init импортирует в эти таблицы наборы случайных данных. Они невелики — 1000 значений для каждой категории, на английском языке.
Изменим данные в столбце passenger_name, используя значения, возвращаемые функциями fake_first_name и fake_last_name:
С помощью функции shuffle_column перемешаем данные в столбце бронирований. В качестве последнего параметра вызова требуется указать столбец, выполняющий функцию первичного ключа:
Page 8: Page 8
Дополнительно исказим суммы и даты бронирований:
Исходные данные — бронирования и билеты:
Измененные данные:
Данные бронирований и билетов анонимизированы.
Page 9: Метки и правила
Метки безопасности
- штатный универсальный механизм хранения атрибутов объектов
- назначаются администратором
- интерпретируются модулем — провайдером меток
- Правила изменения данных
- описываются меткой безопасности для провайдера anon
- на уровне столбцов таблиц
- определяют преобразование: замену на константу или значение
- функции
Комментарии преподавателя
Штатный механизм меток безопасности PostgreSQL позволяет ассоциировать метки с отдельными объектами, в том числе и со столбцами таблиц.
Метка — это атрибут объекта (текстовая строка), который устанавливается администратором, а интерпретируется при обращении к объекту загружаемым модулем — провайдером. Провайдер также определяет, допустима ли метка и разрешено ли применять ее к указанному объекту. PostgreSQL не накладывает ограничений на то, как провайдер должен интерпретировать метки безопасности; он лишь обеспечивает механизм их хранения и поддержку работы модулей-провайдеров. На базе этого механизма может быть реализована, например, система мандатного управления доступом (MAC).
https://postgrespro.ru/docs/enterprise/16/sql-security-label
Для расширения pgpro_anonymizer провайдером меток безопасности выступает модуль anon.
Помимо простого статического изменения с помощью функций, рассмотренного в демонстрации, расширение позволяет определить правила изменения данных (маскирования). Правила могут описывать замену исходного значения как на определенное статическое значение, так и на значение, возвращаемое функцией. При этом можно использовать и пользовательские функции, реализующие необходимую логику.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#DECLARE-MA SKING-RULES
Page 10: Динамическое изменение
Работает для ролей, помеченных как недоверенные
- Обращение к таблице подменяется на обращение к представлению
- anon.sourceschema — схема исходных данных
- anon.maskschema — схема анонимизирующих представлений
- Ограничения и особенности
- поддержка только одной схемы
- необходимость каскадного удаления таблиц
- запрет прямого изменения типа данных
- возможное снижение производительности
Комментарии преподавателя
Динамическое маскирование работает для ролей с установленной меткой безопасности MASKED (недоверенных ролей).
В схеме, указанной в параметре anon.maskschema, создаются представления, одноименные с анонимизируемыми таблицами из схемы anon.sourceschema и изменяющие данные согласно установленным правилам. При этом для недоверенных пользователей путь поиска изменяется таким образом, что при указании целевой таблицы запрос перенаправляется к маскирующему представлению.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#DYNAMIC-MA SKING
У динамического маскирования есть ряд особенностей и ограничений:
● Чтобы удалить исходную замаскированную таблицу, для нее нужно выполнять DROP … CASCADE, что позволяет сразу удалить и зависящее от нее маскирующее представление.
● Система работает только с одной схемой, указанной в параметре anon.sourceschema (по умолчанию — public).
● Когда активировано динамическое маскирование, запрещено изменять тип данных столбца, если на нем есть маска. Чтобы изменить такой столбец, маскирование нужно временно отключить.
● Динамическое маскирование может медленно работать с некоторыми запросами, например соединяющими таблицы по ключу, который маскируется хешированием.
Page 11: Динамическое изменение
Создадим пользователя, для которого будем ограничивать доступ к данным, и пометим его как недоверенного:
Установленные метки безопасности объектов можно увидеть в системном каталоге:
Предположим, что нужно предоставить минимально необходимый доступ к данным пассажиров вспомогательным службам аэропорта. В этом случае номер билета и часть персональных данных пассажира можно скрыть или подменить. Определим правило, скрывающее данные документа, идентифицирующего пассажира — они будут частично маскированы:
Столбец contact_data представлен типом jsonb, для работы с его элементами определим функцию. При включенном параметре anon.restrict_to_trusted_schemas она должна принадлежать одной из доверенных схем:
Из соображений безопасности в правилах маскирования надо явно указывать имя схемы — это не позволит пользователю-злоумышленнику подменить функцию на собственную:
В правиле для столбца укажем вызов этой функции:
Вот созданные нами метки для столбцов:
Page 12: Page 12
Более удобный способ получения информации о правилах изменения — представление anon.pg_masking_rules:
Далее нам необходимо установить исходную (bookings) и анонимизирующую (mask по умолчанию) схемы для базы данных:
Чтобы изменения вступили в силу, нужно переподключиться к базе и активировать механизм динамического маскирования:
Вызов этой функции: проверит состояние расширения и при необходимости вызовет anon.init; при необходимости создаст схему, указанную в параметре anon.maskschema; для таблиц в sourceschema создаст в maskschema одноименные представления, через которые недоверенные пользователи будут видеть маскированные данные; отзовет все права на sourceschema у всех недоверенных ролей; назначит недоверенным ролям необходимые права на схемы anon и anon.maskschema, а также на объекты в них; установит недоверенным ролям путь поиска к схеме anon.maskschema. Вот список созданных маскирующих представлений:
Page 13: Page 13
Подключаемся к базе от имени недоверенного пользователя и выполняем запрос:
В полученных данных видно, что такая анонимизация никак не учитывает смысловой взаимосвязи столбцов, содержащих имя пассажира и его контактные данные (адрес электронной почты). Для получения более правдоподобных данных можно использовать пользовательские подменяющие функции. Путь поиска и права для недоверенного пользователя изменены таким образом, что вместо схемы bookings ему видны объекты из схемы mask:
Доступа к исходным данным у пользователя looser нет:
Посмотрим также на определение представления tickets, подменяющего одноименную таблицу. В нем видны подстановки, соответствующие заданным правилам:
Page 14: Page 14
Изменим правила маскирования для столбцов. Номер билета будем считать конфиденциальным и скроем его, заменив на константу:
А для документа, идентифицирующего пассажира, маскирование отменим:
Page 15: Статическое изменение
Данные в таблицах изменяются по заданным правилам
- anon.anonymize_database() — все данные в базе
- anon.anonymize_table() — отдельная таблица
- anon.anonymize_column() — отдельный столбец таблицы
Комментарии преподавателя
Статическое изменение данных также может выполняться на основе определенных правил маскирования.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#APPLYING-MA SKING-RULES
Функции anon.anonymize_database, anon.anonymize_table и anon.anonymize_column позволяют преобразовать исходные таблицы в соответствии с заранее определенными правилами.
Поскольку при этом перезаписываются все строки таблицы, даже если изменяется только один столбец, такая операция может занять продолжительное время.
Иногда может оказаться быстрее экспортировать анонимизированные данные и повторно загрузить их в базу данных. Если нужно экспортировать базу вместе с анонимизируемыми данными, следует воспользоваться скриптом pg_dump_anon.sh.
https://postgrespro.ru/docs/enterprise/16/pgpro-anonymizer#ANONYMOUS-DUMPS
Page 16: Статическое изменение по правилам
Сейчас данные в схеме m_schema выглядят следующим образом:
Определим правила, которые скроют номер бронирования, не нарушив взаимосвязь таблиц по столбцу book_ref. Применим хеширование: это преобразование является детерминированным. Вычисленное значение хеша будет слишком длинным…
…поэтому мы идем на то, чтобы сохранить только его часть. Конечно, такое сокращение повысит риск коллизии значений.
Для хеширования применяются алгоритм и соль, указанные в параметрах. Обычные пользователи не имеют к ним доступа даже на чтение:
Проверим правила:
Page 17: Page 17
Преобразуем таблицы с применением этих правил:
Результат:
Обратите внимание, что для безопасности преобразующие функции работают с правами вызывающего пользователя:
Page 18: Итоги
Анонимизация позволяет защитить конфиденциальные данные, когда разграничение ролей неприменимо
- Правила изменения данных определяются декларативно с помощью меток безопасности
- Поддерживается статическое и динамическое изменение
- Анонимизация данных влечет накладные расходы
Page 19: Практика
- Настройте правило маскирования столбца с контактными данными таблицы m_tickets так, чтобы почтовые адреса содержали имена и фамилии пассажиров. Экспортируйте данные таблицы в анонимизированном виде от лица недоверенного пользователя. 2. Включите динамическое маскирование. Объявите правило для подмены имени пассажира в таблице m_tickets. Выполните несколько запросов к одной из строк таблицы. Затем перепишите правило так, чтобы использовалась псевдонимизация и снова выполните запросы. Сравните результаты.
Комментарии преподавателя
- Установите расширение и скопируйте небольшую часть данных в таблицу m_tickets из bookings.tickets так, как это сделано в демонстрации.
Напишите функцию, формирующую контактные данные, в которых почтовый адрес имеет вид имя.фамилия@example.com. Поместите эту функцию в доверенную схему и используйте ее в правиле изменения.
Создайте недоверенного пользователя и сделайте выгрузку данных с помощью скрипта pg_dump_anon.sh от его имени.
- Для подмены имен используйте изменчивую функцию anon.fake_first_name. Для псевдонимизации замените ее на anon.pseudo_first_name.
Page 20: 1. Пользовательские правила анонимизации
Установим расширение pgpro_anonymizer в демобазе и инициализируем его.
Создадим в схеме public таблицу m_tickets, в которую скопируем часть данных из таблицы tickets схемы bookings:
Используем функцию, показанную в демонстрации, но добавим подзапрос, формирующий почтовый адрес по переданному аргументу:
Проверим:
В правиле маскирования укажем вызов этой функции:
Взглянем на созданное правило:
И на исходные данные (динамическое маскирование не включено):
Page 21: Page 21
Создадим недоверенного пользователя и выполним выгрузку данных из таблицы под его аккаунтом.
Данные таблицы выгрузились в анонимизированном виде.
2. Подмена и псевдонимизация
Активируем механизм динамического маскирования:
Сформируем правило, подменяющее имя пассажира. Для этого воспользуемся функцией anon.fake_last_name:
Подключаемся как недоверенный пользователь и выполняем несколько одинаковых запросов.
Page 22: Page 22
Подмененные значения каждый раз получаются разные. Псевдонимизация, в отличие от подмены, является детерминированной. Функции, выполняющие псевдонимизацию, всегда будут возвращать тот же результат для того же аргумента (и той же соли, если она передается). Вот список предоставляемых расширением функций псевдонимизации:
Заменим правило на новое, выполняющее псевдонимизацию имени пассажира, где в качестве затравки будем использовать код документа. Это гарантирует нам получение одинакового имени пассажира для одного и того же документа.
Page 23: Уборка
Удалим расширение и объекты, созданные в базе demo, удалим созданную роль и очистим список загружаемых библиотек.