← назад к разделу

Как только в системе появляются пользователи из Европы, всплывает аббревиатура GDPR — и обычно в связке со словами «штраф» и «удаление данных». Разберём регламент глазами разработчика: что считается персональными данными, когда он вас касается, что реально требует от кода и почему главный приём тот же, что и с картами, — хранить как можно меньше.

Главная развилка видна на «праве быть забытым»: сколько мест придётся обойти по запросу на удаление, решает не сам запрос, а то, что вы вообще собрали и куда положили.

«удалите мои данные» — где они успели осесть forget(userId = 42) профиль заказы логи аналитика DELETE выполненконтакты стёртыимя и телефонв каждом заказеосталисьemail в логахи в стектрейсахсобытия с emailкак ключомпрофиль пуст — но имя и email остались в трёх местах из четырёхзапрос «удалите меня» не исполнен deleteпрофиль и контактыanonymizeимя → «удалённый»заказ — для учётатолько user_idимён и email нетчистить нечегоключ — user_hashсвязь с emailжила в профилеи удалена с нимкод трогает два места: профиль удаляем, заказ обезличиваемлоги и аналитику чинить не нужно — имена и email туда не попадали сколько мест обходить, решает не запрос, а модель данныхчего не собрал — того не придётся ни искать, ни удалять

Запрос на удаление обходит все места, где осели данные. Без минимизации DELETE из users закрывает одно место из четырёх; с обезличиванием заказов, чистыми логами и user_hash в аналитике код трогает два, а остальные закрыты заранее.

Обязательно

Что это и когда касается вас

GDPR (General Data Protection Regulation) — регламент Европейского союза о защите персональных данных. Он касается вас, если вы обрабатываете данные людей, находящихся в ЕС, — независимо от того, где расположена компания и серверы. Это не отраслевой стандарт, как PCI DSS, а закон с ощутимыми штрафами: до 20 млн евро или 4% годового оборота — причём берётся бо́льшая из двух величин, а оборот считается мировой и по всей группе компаний, а не по одному юридическому лицу. Для крупной компании это означает, что цифра «20 млн» — нижняя граница, а не верхняя.

Ключевые понятия:

  • Персональные данные — любая информация, по которой можно опознать человека: имя, email, телефон, IP-адрес, идентификатор устройства, геолокация. Отдельно выделяют особые категории (здоровье, биометрия, взгляды) — с ними требования строже. Это определение из регламента ЕС; российский 152-ФЗ даёт похожий, но не дословно совпадающий список — разбор различий есть в статье PII и секреты.
  • Субъект данных — сам человек, чьи данные обрабатываются.
  • Контролёр и процессор — кто определяет, зачем обрабатывать данные (контролёр), и кто обрабатывает по его поручению (процессор, например облачный провайдер).
  • Законное основание — у обработки должна быть причина из списка: согласие, исполнение договора, законное обязательство и другие. Нет основания — нельзя обрабатывать.

Главная стратегия: хранить как можно меньше

GDPR строится на минимизации: собирайте только те данные, которые действительно нужны для задачи, и держите их только столько, сколько нужно. Это же снимает большинство рисков — данных, которых у вас нет, не украдут и не придётся удалять.

  • Не собирайте про запас. Каждое поле анкеты должно отвечать на вопрос «зачем оно этой функции». Дата рождения нужна только для проверки возраста — храните результат проверки, а не саму дату. С оговоркой: возраст растёт, и флаг «18+», выставленный однажды, со временем врёт в обратную сторону — вчерашний семнадцатилетний совершеннолетний, а флаг у него false. Поэтому рядом с флагом держат дату самой проверки и пересчитывают его при следующем обращении, а не считают вечной истиной.
  • Псевдонимизация. Замените прямые идентификаторы суррогатом: аналитика работает с user_hash, а связь user_hash → email лежит отдельно, под строгим доступом. Утечка одной таблицы событий тогда сама по себе не называет имён — это тот же ход, что токенизация карт в PCI DSS. Только не путайте псевдонимизацию с обезличиванием: по регламенту псевдонимизированные данные остаются персональными со всеми требованиями. И user_hash должен считаться с секретной солью: хеш от одного лишь email подбирается за минуты — берут список адресов, хешируют и сверяют.
  • Срок хранения (retention). У каждого набора данных — свой срок жизни, после которого он удаляется или обезличивается автоматически, а не «лежит вечно на всякий случай».

Права субъекта и что они значат для кода

GDPR даёт человеку набор прав, и почти каждое превращается в конкретную задачу в коде. Заложите их в модель заранее — дописывать «право на удаление» в систему, где данные размазаны по десяти таблицам и логам, дорого.

ПравоЧто требует от системы
Доступвыгрузить все данные о человеке в читаемом виде
Исправлениедать отредактировать неверные данные
Удаление («право быть забытым»)удалить или обезличить данные по запросу
Портируемостьотдать данные в машиночитаемом формате (JSON/CSV)
Ограничение и возражениеприостановить обработку, отписать от рассылок

«Право быть забытым» — самое коварное для архитектуры. Удалить строку в таблице users мало: данные человека осели в заказах, логах, аналитике, бэкапах, у процессоров. Реалистичный подход — обезличивание вместо удаления там, где запись нельзя убрать: заказ остаётся для бухгалтерии, но имя и контакты в нём заменяются на «удалённый пользователь».

// Удаление по GDPR: где можно — удаляем, где нельзя (нужно для учёта) — обезличиваем.
void forget(long userId) {
    profileRepo.deleteByUserId(userId);          // профиль и контакты — под удаление
    orderRepo.anonymizeCustomer(userId);         // заказы остаются, но без ПД
    auditLog.record("gdpr_erasure", userId);     // сам факт удаления фиксируем
}

Последняя строка выглядит как нарушение того, что мы только что сказали: пользователя удалили, а его идентификатор всё равно лёг в журнал. Это осознанное исключение. Исполнение запроса на удаление нужно уметь доказать — иначе на вопрос регулятора или самого человека «а вы правда удалили?» ответить нечем. Поэтому в журнале оставляют минимум: идентификатор, дату и сам факт, без имени, адреса и прочих данных. Такая запись живёт по своему сроку хранения и лежит отдельно от рабочих таблиц.

Выгрузка данных (право на доступ и портируемость) — это обход тех же мест, но на чтение: собрать всё, что связано с пользователем, в один экспорт.

Сроки, которые ставят задачи в код

Регламент почти не говорит про технику, зато называет сроки, и именно они превращаются в требования к системе.

Ответ субъекту — месяц. На запрос о доступе, исправлении или удалении отвечают без необоснованной задержки и не позже месяца; для сложных случаев срок продлевают ещё на два, уведомив человека. Месяц выглядит щедро, пока не выяснится, что экспорт собирают вручную по десяти таблицам и трём сервисам, а собирает его один человек, который бывает в отпуске. Практический вывод: выгрузка и удаление должны работать как функция системы, запускаемая по нажатию, а не как задача разработчику. Если подготовка занимает дни, срок съедается ожиданием.

Утечка — 72 часа. Надзорный орган уведомляют в течение 72 часов с момента, когда об утечке узнали, а самих людей — без задержки, если для них есть высокий риск. Отсюда требование, которое выглядит чисто техническим: утечку надо уметь замечать и уметь оценивать. Замечать — это сигналы на аномальный доступ и выгрузки, о чём раздел про журнал в статье про аудит. Оценивать — это возможность быстро ответить, чьи данные и за какой период ушли: без журнала доступа на этот вопрос уходит не 72 часа, а недели. И отсчёт идёт от обнаружения, поэтому «мы не знали» не помогает: не знали, потому что не смотрели.

Срок хранения — ваш собственный. Регламент не называет цифр, он требует не хранить дольше, чем нужно для цели. Значит, цифру называете вы — по каждому набору данных, в документе, и она же стоит в схеме и в фоновой задаче очистки. Отсутствие срока — это и есть нарушение, даже если данные никому не мешают.

день 0 запись создана пока нужна цели живёт целиком цель закрыта имя и почта стёрты срок учёта вышел строка удалена срок копии вышел нет и в копиях

Жизнь записи по срокам: пока она нужна цели, лежит целиком, дальше фоновая задача стирает имя и почту, по сроку учёта удаляет строку, а из копий запись уходит с их собственным сроком.

По российскому закону сроки другие и жёстче на инцидентах: об утечке сообщают в течение суток, а результаты внутреннего разбора досылают в течение трёх суток. Разбор этого — в разделе про 152-ФЗ ниже.

Откуда удалить нельзя: резервные копии и процессоры

«Право быть забытым» разбивается о два места, и оба в статьях обычно только упоминаются. Первое — резервные копии: удалить одну строку из вчерашнего дампа нельзя, а восстановление копии возвращает удалённого пользователя обратно. Второе — процессоры: данные ушли в сервис рассылки, в систему поддержки, в аналитику, и «мы удалили у себя» ничего не значит.

Копии. Работающих подходов три, и обычно берут первый вместе со вторым.

  • Срок жизни копии. Если резервные копии живут тридцать дней, то удалённая запись исчезает из них сама через тридцать дней. Такой подход принимается регуляторами, но при двух условиях: срок задокументирован и действительно соблюдается, а из копии данные не достают для обычной работы — только для восстановления после аварии.
  • Список удалённых и повторное применение. Ведут отдельный, переживающий восстановление список исполненных удалений (только идентификаторы и даты), и после каждого восстановления копии по нему прогоняют удаление заново. Это единственный способ не вернуть человека обратно, восстанавливая базу после аварии, и его надо тренировать вместе с самим восстановлением — иначе про него вспомнят в момент, когда все заняты.
  • Шифрование с уничтожением ключа. Данные каждого человека шифруются своим ключом, удаление — это уничтожение ключа; в копии остаётся то, что расшифровать больше нечем. Подход дорогой (ключ на пользователя, ротация, поиск по зашифрованному) и оправдан для узкого набора особо чувствительных данных, а не для всей базы.

Процессоры. У каждого внешнего сервиса, которому уходят персональные данные, есть три обязанности с вашей стороны: договор об обработке, список того, что именно ему передаётся, и способ передать ему запрос на удаление. Практически это значит, что процедура удаления пользователя — не один метод в вашем коде, а последовательность, в которой есть вызовы наружу: удалить контакт в сервисе рассылки, закрыть обращения в системе поддержки, удалить событие из аналитики. Вызовы наружу падают, поэтому удаление оформляют как задачу с повторами и с состоянием («в остальном удалено, рассылка ждёт»), а факт завершения фиксируют, чтобы ответить человеку.

И то, о чём вспоминают последними: подрядчик процессора. Сервис рассылки сам живёт в чужом облаке, и список субпроцессоров — часть того же договора. Проверять его — не работа разработчика, но знать, что он существует, стоит: вопрос «а где физически лежат наши данные» ответа «в сервисе рассылки» не имеет.

Согласие: где лежит и что значит его отзыв

Согласие названо выше как одно из оснований обработки, и оно же — самое хлопотное. Остальные основания статичны: договор либо есть, либо нет. Согласие даётся, отзывается, сужается, и всё это надо уметь показать.

Согласие — это запись, а не галочка. Галочка в форме живёт до перезагрузки страницы, а показать нужно, на что именно человек согласился, когда и в какой формулировке. Значит, в базе лежит таблица с полями: кто, на какую цель (рассылка, профилирование, передача партнёру — по цели, а не одним флагом «согласен со всем»), когда, версия текста, который ему показали, и способ (галочка в форме, ответ в письме). Версия текста здесь не формальность: текст меняется, и через год вопрос «на что он соглашался» без версии остаётся без ответа.

Одно согласие — одна цель. Общая галочка «согласен с политикой и на рассылку» не работает: согласие должно быть конкретным, а отзыв рассылки не должен отменять обработку по договору. В коде это набор независимых записей, а не поле consent = true.

Отзыв делается так же легко, как дача. Если согласие давалось галочкой при регистрации, отзыв не может требовать письма на бумаге: ссылка в письме и переключатель в профиле. Технически отзыв — не удаление записи, а новая запись со временем отзыва: историю согласий хранят, иначе нечем подтвердить, что рассылка до отзыва была законной.

Что делать с данными, собранными по отозванному согласию. Здесь путают две вещи. Отзыв не делает прошлую обработку незаконной — то, что было сделано до отзыва, остаётся правомерным. Но после отзыва обработка по этой цели прекращается, и данные, у которых нет другого основания, удаляются или обезличиваются. Практически это ровно та же процедура, что и удаление, только частичная: контакт уходит из рассылки, события профилирования обезличиваются, а заказы остаются — у них основание другое, исполнение договора.

Отсюда и требование к модели, которое дешевле заложить сразу: у каждого набора данных о человеке известно, на каком основании он хранится. Тогда отзыв согласия превращается в понятный запрос «удалить всё, что держалось только на этом согласии», а не в разговор «а заказы-то удалять?».

Привычки в коде, которые закрывают большую часть регламента

Практически GDPR сводится к нескольким привычкам, знакомым по безопасной разработке:

  • Минимум данных в модели. Нет поля — нет проблемы. Особые категории (здоровье, биометрия) не заводят без явной необходимости и отдельного основания.
  • Чистые логи. Персональные данные в логе запроса или в стектрейсе — типичное нарушение. Тот же принцип, что и с PII и секретами в логах: в лог идут идентификаторы, а не email и имена.
  • Срок хранения в схеме. Поле created_at плюс фоновая задача, которая удаляет или обезличивает записи старше срока, — а не ручная чистка «когда-нибудь».
  • Шифрование и доступ. Персональные данные шифруются при хранении и передаче, доступ — по принципу наименьших привилегий, обращения к ним — под аудитом.
  • Согласие как данные. Если основание обработки — согласие, храните, на что и когда человек согласился, чтобы это можно было показать и отозвать.

Выгрузка: как собрать и как убедиться, что просит сам человек

Право на доступ и портируемость выше описано одной строкой — «обход тех же мест, но на чтение». Это верно, но именно в реализации выгрузка оказывается сложнее удаления.

Что входит. Все данные о человеке, а не только профиль: заказы, обращения в поддержку, адреса, согласия, история входов, данные, которые вы получили от третьих лиц. Не входят внутренние выводы о нём, если они не относятся к его данным, и данные других людей (переписка, где есть второй участник, отдаётся без его части). Формат — машиночитаемый: JSON или CSV, а не PDF со скриншотами.

Как собирать. Данные размазаны по сервисам, поэтому выгрузка — фоновая задача, а не запрос по кнопке: она обходит сервисы, складывает части в архив и сообщает о готовности ссылкой. Ссылка живёт ограниченное время и требует входа, потому что архив со всеми данными человека — самый лакомый файл из всех, что у вас есть. Складывать его в общедоступное хранилище «на пару дней» — это создать утечку своими руками.

Как проверить, кто просит. Самый неприятный вопрос в этой теме. Выгрузка по одному лишь адресу электронной почты, указанному в письме, — готовый способ собрать данные чужого человека: достаточно написать «я Иван Петров, пришлите мои данные» с похожего адреса. Поэтому запрос выполняют из учётной записи: человек входит и нажимает кнопку в профиле, и тогда его личность уже подтверждена входом. Если учётной записи нет или доступ к ней потерян, личность подтверждают отдельно, и это ручная процедура поддержки с разумным минимумом дополнительных данных — просить паспорт «для надёжности» тоже нельзя, это лишние данные.

Сроки и повторы. Ответ — в тот же месяц, что и на остальные запросы. Повторные запросы того же человека без конца исполнять не обязаны: явно неразумные и чрезмерно частые запросы можно ограничить, но это исключение, а не повод отказать в первом.

Аналитика и третьи стороны

Самый частый источник претензий к сайту — не база и не логи, а то, что подключено к странице: счётчик посещаемости, пиксель рекламной сети, чат поддержки, карта, шрифты с чужого домена, встроенное видео. Каждый такой скрипт получает адрес страницы, адрес пользователя, идентификатор устройства и ставит свои файлы cookie — то есть обрабатывает персональные данные, причём не вами.

Что из этого следует практически.

До согласия — ничего необязательного. Всё, без чего сайт работает (счётчики, реклама, внешнее видео, тепловые карты), подключают только после согласия, а не до. Баннер, который сообщает «мы используем cookie» и ставит их сразу, не является согласием вовсе. Технически это значит, что скрипты сторон грузятся кодом после ответа пользователя, а не тегами в разметке, и отказ должен работать так же одним нажатием, как согласие.

Своя аналитика дешевле. Счётчик, который считает просмотры у вас на сервере по данным запроса и не ставит cookie, снимает почти весь этот разговор: данные не уезжают третьей стороне, согласие на необязательные файлы не требуется. Для большинства сайтов такого счётчика хватает, а отказ от внешнего избавляет и от баннера, и от вопросов.

Шрифты и статика с чужих домен — тот же канал: браузер обращается к чужому серверу, и тот видит адрес пользователя. Это одна из самых частых претензий именно потому, что выглядит безобидно. Лечится тем, что шрифты и библиотеки раздают со своего домена.

Данные в аналитике обезличивают. В события аналитики не кладут email и телефон, а кладут суррогатный идентификатор с секретной солью, как описано в разделе про минимизацию. Тогда утечка аналитики не называет имён, а запрос на удаление сводится к удалению связи суррогата с человеком.

И общее правило, которое экономит больше всего сил: список третьих сторон, подключённых к странице, существует как документ, и новая подключённая сторона — это решение, а не результат того, что кто-то вставил тег в разметку. Ровно то же требование есть в стандарте про карточные данные — для страницы оплаты там обязателен учёт всех скриптов.

Резидентность данных

Отдельная тема — где физически лежат данные. Здесь легко смешать два разных требования и получить решение, которое не закрывает ни одно.

Европейский регламент не требует держать данные в Европе: он ограничивает вывоз за её пределы и требует, чтобы у принимающей стороны были сопоставимые гарантии — либо признанные достаточными правила страны, либо специальный договор. На практике проще выбрать европейский регион у облачного провайдера, чем оформлять и поддерживать эти основания.

Российский закон говорит о другом и жёстче: персональные данные граждан должны первично собираться и храниться в базах на территории России. Европейский регион здесь не поможет вообще — он закрывает первую задачу и никак не закрывает вторую. Нужна база в российском дата-центре, и именно в неё данные попадают первыми.

Если продукт работает и там, и там — это две отдельные площадки, а не одна «где-нибудь поближе к пользователю». И в обоих случаях следят за одним и тем же: чтобы данные не уезжали в чужой регион «случайно» — через резервные копии, аналитику или внешний сервис рассылок. Это архитектурное решение, и принимают его до запуска, а не после.

Дополнительно: при первом чтении можно пропустить

Глубже: 152-ФЗ: что отличается от GDPRрасширенное

Для сервиса с российскими пользователями ближе не европейский регламент, а закон 152-ФЗ «О персональных данных», и большинство привычек из этой статьи ему подходят. Отличия в четырёх местах, и каждое влияет на код и инфраструктуру.

Уведомление до начала обработки. Оператор персональных данных, то есть почти любая компания с формой регистрации, подаёт уведомление в Роскомнадзор до начала обработки; исключений с 2022 года почти не осталось. В уведомлении перечисляют цели, категории данных и субъектов, меры защиты и место хранения. Для разработчика это означает, что список «какие поля о пользователе мы храним и зачем» существует как документ, и новое поле в таблице users это изменение, о котором должны знать не только вы.

Локализация. Первичный сбор, запись и хранение данных граждан России ведут в базе на территории страны. Копировать за рубеж можно, но первая запись обязана быть здесь, и трансграничная передача требует отдельного уведомления. Практически это ограничивает выбор облака и управляемых сервисов: база пользователей живёт у российского провайдера, а иностранный сервис аналитики или рассылки получает данные только после того, как они записаны здесь, и с уведомлением.

Уровни защищённости и меры. Закон делит обработку на уровни защищённости УЗ-1…УЗ-4 по категориям данных (специальные, биометрические, общедоступные, иные) и объёму, а приказ ФСТЭК № 21 задаёт набор мер под каждый уровень: идентификация и аутентификация, разграничение доступа, регистрация событий, антивирус, защита среды виртуализации. Для обычного сервиса с именами и email это УЗ-4 или УЗ-3, и меры из этого раздела (журнал, доступ по ролям, шифрование при передаче) закрывают большую часть; на верхних уровнях требуются сертифицированные средства защиты, и это уже не про код.

Инциденты и ответственность. Об утечке сообщают в Роскомнадзор в течение суток с момента обнаружения и в течение трёх суток досылают результаты разбора. С 2025 года штрафы за утечки стали оборотными, то есть считаются от выручки, а не фиксированной суммой, и это единственный аргумент, который убеждает заложить в план работу из раздела про проверки в сборке.

Коротко разница выглядит так:

ВопросGDPR152-ФЗ
Что делают до начала обработкиоценивают риски, ведут учёт обработок внутриподают уведомление в Роскомнадзор
Где хранятвывоз из ЕС только при гарантиях, хранение в ЕС не обязательнопервичный сбор и хранение данных граждан России — в стране
Согласиеодно из шести оснований, часто не главноеосновной рабочий механизм, форма и содержание описаны подробно
Меры защитывыбирает оператор по рискунабор мер под уровень защищённости по приказу ФСТЭК № 21
Срок на ответ субъектумесяц, продление ещё на дватридцать дней, продление до шестидесяти
Уведомление об утечкенадзорный орган — 72 часаРоскомнадзор — сутки, результаты разбора — трое суток
Штрафдо 20 млн евро или 4 % мирового оборотаоборотные штрафы с 2025 года

Что общее с GDPR и что делает код по одним и тем же правилам: согласие и цели, право на доступ и удаление, хранить как можно меньше и не дольше, чем нужно, обезличивать в аналитике и тестовых средах. Что отличается на практике: в GDPR правила игры задают риск и ответственность, в 152-ФЗ формальные требования, уведомления и локализация, поэтому под 152-ФЗ сначала оформляют документы и место хранения, а под GDPR сначала минимизируют данные. Сервис, работающий на оба рынка, выполняет оба списка, и дешевле всего это делается одним журналом данных: где какое поле хранится, зачем, сколько и кому передаётся.

Коротко

  • GDPR — закон ЕС о персональных данных: касается всех, кто обрабатывает данные людей из ЕС, штраф — 20 млн евро или 4 % мирового оборота группы, что больше. Персональные данные — всё, по чему можно опознать человека, и у обработки каждого набора есть законное основание.
  • Главный приём — минимизация: собирать только нужное и хранить ограниченный срок; данных, которых нет, не украдут.
  • Права субъекта (доступ, удаление, портируемость) — это конкретные задачи в коде, и «право быть забытым» часто реализуется обезличиванием там, где запись нельзя удалить (заказы, учёт).
  • Для кода это: минимум полей, чистые логи, срок хранения в схеме, шифрование, аудит доступа, хранение данных в нужном регионе.
  • 152-ФЗ: уведомление в Роскомнадзор до обработки, первичное хранение данных граждан России в стране, уровни защищённости с мерами по приказу ФСТЭК № 21, уведомление об утечке за сутки и оборотные штрафы; общее с GDPR это минимизация, цели и права субъекта.
  • Сроки регламента становятся требованиями к системе: ответ субъекту — месяц, значит выгрузка и удаление работают по нажатию; уведомление об утечке — 72 часа от обнаружения, значит нужны сигналы на аномальный доступ и журнал, по которому видно, чьи данные ушли.
  • Из резервных копий выборочно не удаляют: короткий срок жизни копии плюс список исполненных удалений, который прогоняют после каждого восстановления. Внешние сервисы — часть той же процедуры: договор, список переданного и вызов наружу с повторами.
  • Согласие — запись с целью, датой и версией текста, отзыв так же прост, как дача, и прекращает обработку только по своей цели; у каждого набора данных известно основание.
  • Выгрузку собирает фоновая задача, ссылка живёт недолго и требует входа, а личность запрашивающего подтверждает вход в учётную запись, а не адрес в письме.
  • Необязательные скрипты сторон (счётчики, реклама, чужие шрифты) подключают только после согласия, а свой счётчик снимает большую часть вопроса.

Что почитать дальше