Перейти к основному содержимому

Защита MCP-серверов: OAuth, привязка к аудитории и запутанный заместитель

Продвинутый
What you'll learn
  • Понять, почему удалённый (HTTP) MCP-сервер является сервером ресурсов OAuth 2.1, а не просто эндпоинтом с API-ключом
  • Проследить рукопожатие обнаружения: 401 → Protected Resource Metadata → Authorization Server Metadata → токен
  • Объяснить привязку токена к аудитории (RFC 8707) и почему она не даёт токену одного сервиса работать на другом
  • Назвать ловушку запутанного заместителя и единственное правило, которое её закрывает: никогда не пробрасывать токен клиента в вышестоящий API
  • Применить короткий чек-лист усиления безопасности перед тем, как выставить MCP-сервер в интернет

MCP превратился из новинки в способ по умолчанию, которым агенты добираются до инструментов — а значит, MCP-серверы теперь стоят перед реальными данными и реальными действиями. Локальный сервер, который вы запускаете через STDIO, доверяет своему окружению: он читает учётные данные из переменных окружения, и защищать сетевую границу не нужно. В тот момент, когда вы делаете тот же сервер удалённым (HTTP), любой, кто может дотянуться до URL, может попытаться его вызвать. Это превращает задачу в проблему авторизации, и спецификация MCP отвечает на неё OAuth 2.1 — а не самодельной схемой с API-ключами.

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

Три роли

OAuth разбивает задачу на три стороны. MCP аккуратно ложится на них:

Кто есть кто в потоке MCP OAuth
Нажмите Enter или пробел, чтобы перевернуть карточку. Используйте стрелки влево и вправо для перехода между карточками.Показан термин.
1 / 3

Ключевой сдвиг в мышлении: MCP-сервер сам никогда не обрабатывает вход. Он лишь проверяет токены, выданные кем-то другим. Именно это разделение позволяет поставить готового поставщика идентификации перед сервером, который вы написали.

Рукопожатие обнаружения

Клиент не должен заранее быть настроен на то, где аутентифицироваться. MCP делает обнаружение автоматическим, управляемым 401:

Guided walkthrough1 of 6
  1. Самый первый запрос уходит пустым. Сервер отклоняет его с HTTP 401 Unauthorized и заголовком WWW-Authenticate, указывающим на URL его resource-metadata.

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

Привязка к аудитории: несущее правило

Вот тот сценарий отказа, ради предотвращения которого существует привязка к аудитории. Скажем, у пользователя есть токен, выданный для calendar.example.com. Вредоносный (или просто небрежный) MCP-сервер на evil.example.com обманом заставляет клиент отправить этот токен ему. Если evil его примет, он может тут же вызвать API календаря от имени пользователя. Токен одного сервиса сработал на другом. Граница безопасности OAuth только что рухнула.

Решение — Resource Indicators (RFC 8707):

Guided walkthrough1 of 3
  1. Как в запросе на авторизацию, так и в запросе на токен клиент ОБЯЗАН включить параметр resource, установленный в канонический URI MCP-сервера, который он намеревается вызвать — например resource=https://mcp.example.com. Он отправляет его, даже если не уверен, что AS его поддерживает.

Параметр resource в запросе на авторизацию (URL-кодированный)

&resource=https%3A%2F%2Fmcp.example.com

Канонические URI строги: https://mcp.example.com и https://mcp.example.com:8443/mcp допустимы; mcp.example.com (без схемы) и https://mcp.example.com#frag (фрагмент) — нет. Для совместимости предпочитайте форму без завершающего слэша.

Запутанный заместитель: никогда не пробрасывайте токен

Это та ошибка, которая превращает благонамеренный MCP-сервер в прокси атакующего. Это та же самая проблема запутанного заместителя из безопасности агентов, заострённая до одного конкретного правила.

MCP-серверу часто нужно вызвать вышестоящий API (GitHub, сервис базы данных, другой SaaS). Возникает соблазн взять токен, который передал вам клиент, и переслать его наверх. Не делайте этого. Спецификация категорична: MCP-сервер НЕ ДОЛЖЕН пробрасывать токен, полученный от клиента.

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

Watch out
  • Если ваш MCP-сервер вызывает вышестоящий API, он действует как ОТДЕЛЬНЫЙ OAuth-клиент для этого API и получает СВОЙ СОБСТВЕННЫЙ токен от вышестоящего сервера авторизации. Два независимых токена, две независимые аудитории. Токен клиента останавливается у вашей двери.

Предполётный чек-лист усиления безопасности

Прежде чем удалённый MCP-сервер коснётся публичного интернета:

Guided walkthrough1 of 7
  1. Все эндпоинты AS ДОЛЖНЫ работать по HTTPS. Redirect URI ДОЛЖНЫ быть HTTPS или localhost — ничего иного.

Проверьте себя

Проверьте себя

0/4
  1. Удалённый MCP-сервер получает запрос без токена доступа. Что спецификация требует сделать в первую очередь?
  2. От чего защищает привязка токена к аудитории (RFC 8707)?
  3. Вашему MCP-серверу нужно вызвать вышестоящий API GitHub. Что он должен сделать с токеном доступа, который прислал ему клиент?
  4. Для STDIO (локального) MCP-сервера — как спецификация предписывает обращаться с учётными данными?

Источники и дополнительное чтение