Почему бы просто не блокировать агентов для чувствительных действий?
Некоторые действия в вашем 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:
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?
Часто смешиваются три вопроса:
- Кто или что действует? Это actor evidence: interactive person, person with AI assistance, agent или Unknown, с основанием вроде verified или declared.
- Какой credential был предъявлен? Session cookie, API key, OAuth access token.
- Можно ли этому 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 вам всегда нужен хороший ответ на третий вопрос, а первый используется для выбора того, насколько дополнительной уверенности запросить.
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, без изменений.
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.
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:
- Записывайте tier, actor class, basis, тип credential и step-up, который потребовала бы ваша policy.
- Проверяйте выборки high-tier requests по class. Используют ли легитимные agents delegated credentials или повторно используют user sessions?
- Исправьте обнаруженные пробелы, часто за счет предложения scoped credentials, прежде чем включать enforce.
- Включите 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 и его результат.
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.
Источники
- RFC 6749: The OAuth 2.0 Authorization Framework: scoped, delegated credentials для clients
- RFC 9700: Best Current Practice for OAuth 2.0 Security: current security guidance для OAuth deployments
- RFC 7009: OAuth 2.0 Token Revocation: отзыв grant без изменения credentials пользователя
- RFC 9470: OAuth 2.0 Step Up Authentication Challenge Protocol: указание, что требуется более сильная или более свежая authentication
- RFC 8693: OAuth 2.0 Token Exchange: claim
act(actor) для delegation - MCP specification 2026-07-28: Authorization: MCP servers как OAuth 2.1 resource servers
- NIST SP 800-63B: Authentication and Authenticator Management: guidance по reauthentication
- W3C Web Authentication (WebAuthn) Level 3: standard, лежащий в основе passkey prompts
- RFC 9421: HTTP Message Signatures: что устанавливает verified agent signature