Files
progcode/editorial/agent-rewrites/099.json
T

8 lines
22 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"index": 99,
"slug": "editorial-2025-04-practice-ai-data-privacy",
"title": "Перед AI-инструментом данные должны пройти четыре независимые проверки",
"excerpt": "Практический маршрут для безопасной передачи контекста: классификация записи, условия сервиса, egress и scoped authorization с воспроизводимым fail-closed тестом.",
"contentHtml": "<p>Инженер открывает AI-чат, чтобы разобраться с ошибкой, и вставляет десять строк production-лога. В строках остаются email, внутренний идентификатор и фрагмент заголовка запроса. Ответ выглядит полезным, но по нему нельзя понять, какие ещё данные добавила выбранная поверхность, какой endpoint получил запрос и имел ли сотрудник право передавать именно эту запись.</p>\n<p>Здесь полезно разделить четыре независимых вопроса: что находится во фрагменте, разрешает ли policy выбранную обработку, куда технически уйдёт запрос и кто выдал полномочия на конкретный scope. «Корпоративный» аккаунт, allow-list в firewall или согласие в чате отвечает только на часть вопросов. Если любой из них не доказан, безопасный результат — остановить отправку и оставить причину для следующей проверки.</p>\n<h2>Начните с записи, а не с инструмента</h2>\n<p>До открытия внешнего интерфейса зафиксируйте объект передачи. У него должны быть <code>recordId</code>, версия, источник, владелец данных и назначенный класс. Класс описывает содержимое, а не право отправить его наружу: <code>public</code>, <code>internal</code> и <code>restricted</code> — это свойства данных, но не готовое разрешение для любого сервиса.</p>\n<p>Минимальная карточка должна связывать данные с решением. В ней укажите цель, requester (инициатора), назначение, версию policy, условие хранения, срок действия и ссылку на полномочие владельца. Не подменяйте неизвестный класс словом «внутренний» и не переносите разрешение с соседнего файла: другой record, режим или endpoint создаёт новое решение.</p>\n<figure><img src=\"/assets/editorial/2025/ai-data-privacy-2025-egress-review.svg\" alt=\"Пошаговая схема проверки AI-контекста: record и класс данных, policy и договор, egress-маршрут, права и срок полномочия; несовпадение ведёт в safe stop\" loading=\"lazy\" /><figcaption>Учебный маршрут отделяет доказательства до действия от самого hand-off. Любое несовпадение возвращает safe stop; схема не выполняет сетевой запрос.</figcaption></figure>\n<h2>Видимый prompt не равен исходящему запросу</h2>\n<p>Поле чата показывает только часть контекста. Конкретный продукт может добавить историю диалога, имя репозитория, открытый файл, результаты поиска, выбранные расширения или служебные параметры. Это не универсальное свойство всех AI-инструментов: состав нужно проверять для конкретной поверхности, тарифного режима и включённых функций.</p>\n<p>Документация GitHub для Copilot Chat в GitHub прямо описывает обработку пользовательского ввода вместе с контекстом репозитория и, в некоторых случаях, результатами Bing. В той же документации указано, что ответы нужно проверять, а для чувствительного кода — просматривать и тестировать результат. Поэтому в карточке фиксируйте не только текст вопроса, но и surface, включённые источники контекста и фактическое назначение.</p>\n<p>После формирования запроса нужен второй барьер: prompt builder не должен принимать данные, пока детерминированная проверка не вернула разрешённый исход. Это не оценка качества ответа модели. Её результат может быть неверным даже при полностью разрешённом payload, поэтому проверка безопасности и проверка корректности ответа остаются разными этапами.</p>\n<h2>Четыре проверки, которые нельзя слить в одну</h2>\n<p>Первая проверка отвечает за содержимое: классификатор или владелец данных подтверждает, что record относится к заявленному классу после маскирования. Вторая отвечает за условия обработки: policy и договор должны относиться к выбранному продукту, режиму, региону и сроку хранения. Слово «анонимизированный» само по себе не заменяет проверку остаточных идентификаторов и возможности восстановления субъекта.</p>\n<p>Третья проверка отвечает за маршрут. Allow-list говорит, что соединение разрешено к определённому назначению, но не делает любой payload допустимым. Укажите endpoint, прокси, включённый поиск и дополнительные интеграции. Если правило разрешает домен шире, чем договорённый сервис, это повод сузить маршрут или остановить отправку.</p>\n<p>Четвёртая проверка отвечает за полномочия. Requester должен иметь доступ к record, а владелец должен разрешить цель, объём, назначение и срок. Авторизация без <code>recordId</code> и expiry не даёт воспроизводимого scope. Принцип zero trust NIST формулирует похожую границу: доверие не следует выводить только из сетевого положения или принадлежности устройства, а аутентификацию и авторизацию нужно выполнять для конкретного ресурса.</p>\n<div class=\"table-scroll\"><table><caption>Как читать результат pre-flight проверки</caption><thead><tr><th scope=\"col\">Контроль</th><th scope=\"col\">Что доказывает</th><th scope=\"col\">Чего не доказывает</th><th scope=\"col\">Действие при пробеле</th></tr></thead><tbody><tr><td>Класс record</td><td>Содержимое отнесено к правилу с владельцем и версией</td><td>Что внешний сервис вправе его обрабатывать</td><td>Остановить и запросить классификацию</td></tr><tr><td>Policy и условия сервиса</td><td>Для выбранной surface описаны обработка, хранение и режим</td><td>Что запрос пошёл именно по этому маршруту</td><td>Проверить конкретный план, endpoint и дату действия</td></tr><tr><td>Egress allow-list</td><td>Сеть допускает заявленное техническое назначение</td><td>Что payload соответствует policy и полномочиям</td><td>Не отправлять данные до сверки с классом и scope</td></tr><tr><td>Scoped authorization</td><td>Конкретный requester получил срок и цель для record</td><td>Что сервис не добавит другой контекст</td><td>Получить новое разрешение и проверить surface</td></tr><tr><td>Request trace</td><td>Виден фактический outbound payload и destination</td><td>Что ответ модели точен или безопасен для публикации</td><td>Отделить расследование передачи от ревью ответа</td></tr></tbody></table></div>\n<h2>Воспроизводимый fail-closed пример</h2>\n<p>Ниже — самостоятельный пример для Node.js 20 и новее. Он работает только с объектами в памяти, не читает файлы, не вызывает модель и не делает HTTP-запрос. Входы с префиксом <code>synthetic-</code> намеренно учебные. Команда запуска показывает отрицательный путь: restricted-класс блокирует hand-off даже при наличии пользователя и маршрута.</p>\n<pre><code>const request = {\n recordId: 'synthetic-log-v1',\n dataClass: 'restricted',\n serviceCondition: 'synthetic-reviewed-retention',\n destination: 'synthetic-ai-boundary-alpha',\n requester: 'synthetic-engineering-read',\n authorization: {\n scope: 'synthetic-log-v1',\n purpose: 'synthetic-debugging',\n expiresAt: '2026-12-31T00:00:00Z'\n }\n};\n\nconst policy = {\n allowedClasses: ['synthetic-public'],\n serviceCondition: 'synthetic-reviewed-retention',\n destination: 'synthetic-ai-boundary-alpha',\n purpose: 'synthetic-debugging'\n};\n\nfunction decide(input, rules, now) {\n const checks = {\n classAllowed: rules.allowedClasses.includes(input.dataClass),\n serviceReviewed: input.serviceCondition === rules.serviceCondition,\n routeAllowed: input.destination === rules.destination,\n scopeMatches: input.authorization.scope === input.recordId,\n purposeMatches: input.authorization.purpose === rules.purpose,\n authorizationActive: input.authorization.expiresAt &gt; now.toISOString()\n };\n\n const allowed = Object.values(checks).every(Boolean);\n return {\n decision: allowed ? 'hand-off' : 'stop',\n reason: allowed ? null : Object.entries(checks).filter(([, ok]) =&gt; !ok).map(([name]) =&gt; name),\n egressPerformed: false\n };\n}\n\nconst result = decide(request, policy, new Date('2026-08-02T12:00:00Z'));\nconsole.log(JSON.stringify(result, null, 2));</code></pre>\n<p>Запустите сохранённый фрагмент командой <code>node preflight.mjs</code>. Ожидаемый результат содержит <code>\"decision\": \"stop\"</code>, причину <code>classAllowed</code> и <code>\"egressPerformed\": false</code>. Важно, что функция не строит prompt и не передаёт его HTTP-клиенту. В реальном проекте замените учебные справочники на версионированную policy, но сохраните такой же отрицательный контракт.</p>\n<p>Положительный результат тоже ограничен. Если заменить класс на <code>synthetic-public</code>, функция проверит только перечисленные поля. Она не доказывает реальное поведение поставщика, полноту сетевого журнала, юридическое основание обработки или отсутствие скрытого контекста в интерфейсе. Это gate перед следующим полномочным шагом, а не сертификат безопасности.</p>\n<h2>Если данные уже отправили</h2>\n<p>Сначала остановите повторение: отключите интеграцию или запретите дальнейший egress для этой surface. Не удаляйте единственную копию доказательств до согласования с владельцем расследования. Сохраните минимум, необходимый для анализа: время, requester, идентификатор операции, destination, режим продукта и классификацию без копирования чувствительного payload в новый тикет.</p>\n<p>Затем разделите два вопроса. Факт передачи устанавливается по журналам клиента, прокси и поставщика, если они доступны. Состав исходного payload устанавливается по журналу формирования запроса, а не по ответу модели. Если одного из журналов нет, это ограничение результата расследования, а не основание считать, что утечки не было.</p>\n<h2>Порядок pre-flight для команды</h2>\n<ol><li><strong>Назовите record.</strong> Зафиксируйте <code>recordId</code>, версию, источник, владельца и цель. В заявке используйте ссылку или безопасный отпечаток, а не необработанный лог.</li><li><strong>Определите класс.</strong> Проверьте персональные данные, секреты, токены, клиентский код и косвенные идентификаторы после всех преобразований. Если классификация не подтверждена, результатом считается stop.</li><li><strong>Выберите конкретную surface.</strong> Запишите продукт, тарифный режим, историю, repository context, web search и расширения. Не переносите вывод из другого аккаунта или интерфейса.</li><li><strong>Сверьте условия обработки.</strong> Найдите действующие policy и договорные условия для выбранного режима: retention, обучение, регион, субподрядчики и срок. Ссылка на общий сайт продукта недостаточна.</li><li><strong>Проверьте egress.</strong> Сопоставьте endpoint, proxy и сетевое правило с разрешённым назначением. Доступный порт или удачный DNS-ответ не являются допуском payload.</li><li><strong>Проверьте полномочия.</strong> Сопоставьте requester, owner, record, purpose, destination и expiry. Устаревшее «команде можно» не заменяет scoped authorization.</li><li><strong>Проведите synthetic-тест.</strong> Для разрешённого и запрещённого fixture проверьте decision, reason и отсутствие вызова внешнего клиента на stop. Сохраните версию правил и дату прогона.</li></ol>\n<h2>Ограничения применимости</h2>\n<p>Этот маршрут не классифицирует данные автоматически и не заменяет DLP, privacy review, договор с поставщиком, управление доступом или требования закона. NIST AI RMF — добровольная рамка для управления рисками AI; она помогает организовать функции govern, map, measure и manage, но не выдаёт разрешение на конкретную запись. Решение о законности обработки остаётся у вашей организации и зависит от юрисдикции и контекста.</p>\n<p>Локальная модель уменьшает внешний маршрут, но не отменяет права доступа, локальное хранение журналов и риск попадания секрета в историю. Маскирование уменьшает объём, но может оставить комбинацию полей, по которой субъект восстанавливается. Человеческое согласование полезно для спорных случаев, но оно не должно быть единственным барьером, если запросы проходят через автоматическую интеграцию.</p>\n<p>Проверка также не говорит, что ответ модели верен. Для кода нужны ревью, тесты и сканирование зависимостей; для инцидента — независимое подтверждение фактов; для решения о клиенте — отдельная процедура. Без этих этапов безопасный hand-off всё равно может привести к неверному действию.</p>\n<h2>Критерий готовности</h2>\n<p>Путь можно включать для конкретного типа данных, если другой инженер воспроизведёт его без устного контекста. Должны существовать версия классификации, ссылка на policy для конкретной surface, запись проверенного destination, scoped authorization и журнал решения. Негативный тест должен показывать stop при restricted-классе, чужом scope, истёкшем сроке и неизвестном endpoint.</p>\n<p>Если хотя бы одно доказательство отсутствует, не называйте результат «разрешённым». Оставьте данные локально, верните причину отказа и назначьте владельца следующего вопроса. После появления недостающего evidence повторите весь pre-flight: изменение режима, маршрута или версии record делает старое решение неприменимым.</p>\n<h2>Проверяемые источники</h2>\n<ul><li><a href=\"https://docs.github.com/copilot/responsible-use/chat-in-github\" target=\"_blank\" rel=\"noopener noreferrer\">GitHub Docs: Responsible use of GitHub Copilot Chat in GitHub</a> — официально описывает обработку ввода вместе с контекстом репозитория и возможным веб-поиском. Это пример одной конкретной поверхности, а не утверждение о поведении всех AI-инструментов.</li><li><a href=\"https://doi.org/10.6028/NIST.AI.600-1\" target=\"_blank\" rel=\"noopener noreferrer\">NIST AI 600-1: Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile</a> — официальная добровольная рамка для govern, map, measure и manage рисков генеративного AI. Она не заменяет policy вашей организации и не разрешает передачу конкретного payload.</li><li><a href=\"https://csrc.nist.gov/pubs/sp/800/207/a/final\" target=\"_blank\" rel=\"noopener noreferrer\">NIST SP 800-207A: A Zero Trust Architecture Model for Access Control in Cloud-Native Applications</a> — официальный материал о granular access policy, identity и egress gateway. Он поддерживает разделение сетевого маршрута и авторизации, но не проверяет вашу конфигурацию.</li></ul>"
}