Перейти к основному содержимому
РУКОВОДСТВО

Как защищать чувствительные действия, не блокируя легитимных агентов

Практическая модель, которая помогает безопасно выполнять изменения в аккаунтах и другие операции с высоким влиянием, при этом позволяя легитимным автоматизированным клиентам выполнять полезную работу в вашем app.

Toshendra Sharma

Автор Toshendra SharmaОснователь и CEO, AgentCredia · Updated November 13, 2026

Продвинутый · 10 мин чтения

Почему бы просто не блокировать агентов для чувствительных действий?

Некоторые действия в вашем application важнее других. Изменить пароль, добавить участника команды, экспортировать data, удалить project, approve order: если любое из них происходит без надлежащих полномочий, ущерб реален.

В то же время все больше легитимной работы в вашем app выполняет automation. Пользователь просит assistant обновить настройки. Партнерская integration создает записи по расписанию. Internal agent создает support tickets. Блокировка каждого automated client на чувствительных route ломает эту работу и возвращает людей к ручным действиям или к обходным путям, которые сложнее защитить.

Ответ не в том, чтобы "block agents" или "trust agents". Нужна модель, в которой риск действия, полномочия, стоящие за request, и evidence об actor each играют отдельную роль. Это руководство строит такую model. Более широкий подход к этому описан в designing app-level policies for humans and AI agents.

Step 1: Разделите свои routes по уровню риска

Начинайте с классификации действий, а не клиентов. Для большинства applications подходит простая трехуровневая схема:

Уровень Примеры Требование по умолчанию
Низкий Читать public data, search, view own dashboard Обычная authentication, если она есть
Средний Создавать или редактировать свой content, приглашать viewer Authenticated, authorized для ресурса
Высокий Менять credentials, менять ownership, bulk export, delete, approve Authorized плюс step-up или review

Запишите уровень в route configuration, чтобы это было видно в code review:

TS
type Tier = "low" | "medium" | "high";

export const routeTier: Record<string, Tier> = {
  "GET /projects": "low",
  "POST /projects": "medium",
  "POST /projects/:id/members": "medium",
  "POST /account/password": "high",
  "POST /exports": "high",
  "DELETE /projects/:id": "high",
};

Уровни меняются медленно и их легко понимать. Все остальное в этом guide опирается на них.

Step 2: Чем отличаются identity, credentials и authorization?

Часто смешиваются три вопроса:

  1. Кто или что действует? Это actor evidence: interactive person, person with AI assistance, agent или Unknown, с основанием вроде verified или declared.
  2. Какой credential был предъявлен? Session cookie, API key, OAuth access token.
  3. Можно ли этому credential выполнять это action над этим resource? Это authorization.

Verified agent signature (RFC 9421) хорошо отвечает на первый вопрос. Она ничего не говорит о третьем, и этот момент подробно рассмотрен в what signed AI agent requests prove, and what they don't. OAuth token с правильным scope отвечает на третий вопрос. О первом он говорит мало. Для high-tier action вам всегда нужен хороший ответ на третий вопрос, а первый используется для выбора того, насколько дополнительной уверенности запросить.

TS
interface Context {
  actor: { actor: "human" | "human_ai" | "agent" | "unknown"; basis: "verified" | "declared" | "inferred" | "unknown" };
  credential: { type: "session" | "oauth" | "api_key"; scopes: string[]; subject: string };
}

function authorized(ctx: Context, action: string, resourceOwner: string): boolean {
  return ctx.credential.subject === resourceOwner && ctx.credential.scopes.includes(action);
}

Authorization никогда не ослабляется из-за благоприятного actor result. Actor context лишь добавляет требования или выбирает между одинаково безопасными путями.

Step 3: Используйте delegated authority для агентов, действующих от имени людей

Когда agent действует от имени пользователя, дайте ему собственный credential с ограниченными полномочиями вместо того, чтобы позволять ему повторно использовать session пользователя. OAuth 2.0 - это стандартный инструмент: пользователь утверждает конкретные scopes для конкретного client, и token фиксирует этот client. RFC 9700, OAuth 2.0 Security Best Current Practice, описывает, как безопасно внедрять это на практике. MCP servers следуют тому же шаблону: MCP authorization specification рассматривает защищенный MCP server как OAuth 2.1 resource server. В нашей публикации who is calling your MCP server? это применено к tool calls.

Это дает именно то, что нужно для чувствительных действий:

  • Token показывает, какой client действует и от чьего имени.
  • Scopes ограничивают его возможности. Scheduling agent с calendar:write не может изменить пароль.
  • Пользователь может отозвать grant, не меняя свои собственные credentials, а OAuth 2.0 Token Revocation (RFC 7009) определяет, как client сообщает authorization server, что token больше не должен быть действителен.
  • Audit logs показывают, что action выполнил agent, а не пользователь.

Если ваш app еще не поддерживает delegated credentials, сделайте это приоритетом для тех actions, которые agents чаще всего требуют. Это самый эффективный control для automated access.

Step 4: Когда стоит запрашивать step-up check?

Step-up означает запрос дополнительной уверенности в момент выполнения чувствительного action. Для OAuth-protected APIs RFC 9470 определяет, как resource server сообщает client, что текущая authentication недостаточно сильная или недостаточно свежая. Правильный step-up зависит от того, кто действует:

  • Interactive person (Human, Human + AI): повторная authentication (см. требования к reauthentication в NIST SP 800-63B), запрос passkey на основе WebAuthn или одноразовый код.
  • Agent с delegated credential: scope, выделенный для high-tier action и явно предоставленный пользователем, либо confirmation, отправленное пользователю вне текущего канала.
  • Unknown: существующая сильная проверка route, без изменений.
TS
type Requirement = "none" | "reauth" | "explicit_scope" | "user_confirmation" | "review";

function stepUp(tier: Tier, ctx: Context): Requirement {
  if (tier !== "high") return "none";
  const { actor } = ctx.actor;
  if (actor === "human" || actor === "human_ai") return "reauth";
  if (actor === "agent" && ctx.credential.type === "oauth") return "explicit_scope";
  if (actor === "agent") return "user_confirmation";
  return "reauth";
}

Обратите внимание: результат Human не отменяет step-up. Он лишь выбирает step-up, подходящий для interactive person. Inferences могут быть ошибочными, поэтому они должны менять форму проверки, а не убавлять ее.

Step 5: Направляйте на human review там, где нужен judgment

Некоторые actions редки, сильно влияют на систему и их трудно безопасно автоматизировать: bulk export customer data, recovery account после потери credentials или удаление organization. Для них review queue часто лучше любого automated rule.

Actor context делает review быстрее и справедливее, потому что дает reviewer evidence: class, basis, использованный credential, историю похожих requests. Reviewer decides. Classification only informs.

TS
function shouldReview(route: string, ctx: Context): boolean {
  const reviewRoutes = new Set(["POST /exports", "POST /account/recover"]);
  if (!reviewRoutes.has(route)) return false;
  return !(ctx.credential.type === "oauth" && ctx.credential.scopes.includes("export:bulk"));
}

Step 6: Выбирайте поведение при отказе для каждого уровня

Actor evaluation может завершиться по тайм-ауту или не иметь evidence. Заранее определите, что должно происходить.

  • Низкий уровень: fail open. Request продолжается normally.
  • Средний уровень: fail open, при этом обычная authorization сохраняется.
  • Высокий уровень: fail closed к существующей strong check. Отсутствие actor evidence никогда не ослабляет защиту и никогда не блокирует request, который иначе прошел бы ваши обычные checks.

Ключевое свойство - симметрия. Сбой в actor evaluation должен оставить action ровно настолько же safe и ровно настолько же available, как и до добавления actor context.

Step 7: Не принимайте существенных решений о людях на основе inferences

Inferred classification - это evidence об interaction, а не факт о человеке. Не отказывайте кому-то в job application, credit decision, exam result, housing или доступе к essential service только потому, что session выглядела автоматизированной или с AI-assistance. В таких flows используйте actor context, чтобы выбрать process, например human review или альтернативный verification path, и убедитесь, что человек может его завершить.

Это и принцип fairness, и практическое правило. Inferences дают false positives, а цена false positive в таких flows ложится на человека, который не сделал ничего плохого.

Step 8: Сначала внедряйте в режиме observation

Прежде чем это начнет влиять на реальные requests, запустите это в режимах observation и preview:

  1. Записывайте tier, actor class, basis, тип credential и step-up, который потребовала бы ваша policy.
  2. Проверяйте выборки high-tier requests по class. Используют ли легитимные agents delegated credentials или повторно используют user sessions?
  3. Исправьте обнаруженные пробелы, часто за счет предложения scoped credentials, прежде чем включать enforce.
  4. Включите enforce для небольшой части одного route, измерьте completion rates, затем расширяйте.

Step 9: Ведите audit trail, который отвечает на вопрос "кто и от чьего имени"

Для каждого high-tier action записывайте достаточно данных, чтобы позже восстановить, что произошло:

  • actor class и basis на момент request,
  • тип credential, client, которому он был выдан, и subject, который он представляет (OAuth 2.0 Token Exchange, RFC 8693, определяет claim act именно для фиксации такого отношения "acting for"),
  • scopes, которые authorizd action,
  • примененное требование step-up или review и его результат.
TS
audit.write({
  action: "project.export",
  actor: ctx.actor,
  client: ctx.credential.type === "oauth" ? clientIdFromToken(req) : undefined,
  subject: ctx.credential.subject,
  scopes: ctx.credential.scopes,
  requirement,
  outcome: "approved",
  at: new Date().toISOString(),
});

С таким trail на вопрос вроде "этот project удалил человек или assistant, и кто это одобрил" есть ясный answer. Это ускоряет incident response и дает пользователям уверенность, что automated help в вашем app подотчетна.

Практический пример

В app для управления projects assistant обновляет сроки выполнения задач для пользователей и иногда пытается экспортировать целые projects.

  • Обновление задачи - это medium tier. Assistant использует OAuth token с tasks:write. Authorized, без step-up. Allowed.
  • Экспорт project - это high tier. У token assistant нет export:bulk. App отправляет пользователю request на confirmation. Пользователь approves, и app выдает scope для этого client.
  • Unknown client пытается выполнить тот же export с повторно использованным session cookie. Срабатывает существующий prompt на re-authentication, точно так же, как и раньше.

Никто не был blocked за то, что является agent. Каждое действие с высоким влиянием выполнялось при явных полномочиях.

Где здесь место Proof of Actor

Proof of Actor обеспечивает в этой модели сторону actor: кто или что действует и на каком основании. Ваш application сохраняет authentication, authorization и final decision. Detect actor, Understand, как каждый class использует ваши чувствительные routes, и Route каждый request на нужный уровень assurance.

Чтобы спроектировать это для вашего application вместе с нашей командой, apply for early access. Для SaaS scenarios более подробно см. SaaS Apps & Websites.

Источники

Постройте это вместе с нами.

Присоединяйтесь к founding developer program Proof of Actor.

Предпочитаете сначала поговорить? Свяжитесь с основателями