Как стать автором
Обновить
240.38

Как обезопасить Spring AI MCP сервер с помощью OAuth2

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров534
Автор оригинала: Daniel Garnier-Moiroux

Команда Spring АйО перевела статью о том, как правильно настраивать безопасность на MCP серверах с использованием возможностей OAuth2 в свете новейшей спецификации MCP, вышедшей в свет 26-го марта 2025-го года, то есть совсем недавно.


Spring AI предлагает поддержку для Model Context Protocol или, сокращенно, MCP, что позволяет ИИ моделям взаимодействовать и получать доступ к внешним инструментам и ресурсам структурированно. С помощью Spring AI разработчики могут создавать свои собственные MCP сервера и давать ИИ моделям доступ к их возможностям всего в несколько строчек кода.

Авторизация и безопасность в MCP

MCP сервера могут работать локально, используя передачу по STDIO. Чтобы сделать MCP сервер доступным для внешнего мира, он должен предоставлять несколько стандартных HTTP эндпоинтов. В то время как MCP сервера, используемые локально и с целями тестирования, могут не требовать строгой аутентификации, продакшен деплойменты нуждаются в строжайшей безопасности и эффективном управлении permission-ами для доступных внешнему миру эндпоинтов. Эта проблема была решена в последней версии спецификации MCP (от 26-го марта 2025), которую выпустили на прошлой неделе. Она закладывает фундамент для безопасных коммуникаций между клиентами и серверами с использованием популярного протокола OAuth2.

Мы не собираемся делать полный обзор OAuth2 в рамках этой статьи, но немного освежить наши знания о нем будет полезно. В черновике спецификации MCP сервер описывается как одновременно и сервер ресурсов (он же OAuth2 Resource Server), и сервер авторизации (он же OAuth2 Authorization Server).

Будучи сервером ресурсов он выполняет проверки для авторизации входящих запросов, проверяя заголовок Authorization. Заголовок должен содержать OAuth2 access_token, который представляет из себя строку, описывающую “разрешения” (permissions-ы) клиента. Этот токен может быть JSON Web Token (JWT) или opaque token, который сам по себе не несет никакой информации. Если токен отсутствует или невалиден, (неправильно сформирован, истек, неверный получатель и т.д.), MCP сервер, будучи сервером ресурсов, отклоняет запрос. При использовании таких токенов типичный запрос может выглядеть вот так:

curl https://mcp.example.com/sse
    -H "Authorization: Bearer <a valid access token>"

В качестве сервера авторизации, MCP сервер должен также обладать способностью выпускать access_token`ы для клиентов безопасным образом. Прежде чем выпустить токен, сервер должен проверить креды клиента и, в некоторых случаях, identity клиента, который пытается получить доступ к серверу. Сервер авторизации принимает решения по характеристикам токена, таким как дата его истечения, scope-ы и т.д. 

Используя Spring Security и Spring Authorization Server, мы можем легко добавить обе эти возможности к существующему Spring MCP серверу.

Добавление OAuth2 к вашему Spring MCP серверу

В приведенном примере мы добавим поддержку OAuth 2 к тестовому MCP серверу, который предоставляет дополнительные  "погодные" данные (температура, влажность и т.д.) для LLM.  Исходные коды MCP сервера можно найти в репозитории с примерами для Spring AI. Мы не будем заострять внимание на действиях клиентской стороны, только убедимся в том, что наш сервер может выпускать токены и валидировать их.

Прежде всего, импортируем необходимые нам Boot стартеры в pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>

Далее, сконфигурируем OAuth2 клиент в нашем файле application.properties, чтобы мы могли запрашивать токены доступа:

spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id=mcp-client
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret={noop}secret
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-authentication-methods=client_secret_basic
spring.security.oauth2.authorizationserver.client.oidc-client.registration.authorization-grant-types=client_credentials

Это самый простой из возможных клиентов. Мы можем взаимодействовать с сервером авторизации напрямую через POST запросы, браузер не нужен, и мы будем использовать прописанные в коде логин и пароль mcp-client / secret.

Последний шаг — включить использование возможностей авторизационного сервера и сервера ресурсов. Мы сделаем это, создав конфигурационный класс для возможностей по безопасности, например, SecurityConfiguration, в котором мы дадим доступ к бину SecurityFilterChain:

import static org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer.authorizationServer;

@Configuration
@EnableWebSecurity
class SecurityConfiguration {

	@Bean
	SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		return http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
			.with(authorizationServer(), Customizer.withDefaults())
			.oauth2ResourceServer(resource -> resource.jwt(Customizer.withDefaults()))
			.csrf(CsrfConfigurer::disable)
			.cors(Customizer.withDefaults())
			.build();
	}
}

Эта цепочка фильтров сделает несколько вещей:

  • Гарантирует, что каждый запрос аутентифицируется. Благодаря этому, наш MCP сервер будет разрешать только запросы с access_token.

  • Разрешает использование как Spring Authorization Server, так и Spring Resource Server.

  • Отключает CSRF (Cross-Site Request Forgery). MCP сервер не предназначен для взаимодействия с браузерами, поэтому CSRF-защита здесь не нужна.

  • Включает поддержку CORS (Cross-Origin Resource Sharing), чтобы мы могли продемонстрировать сервер при помощи MCP инспектора.

Эти действия обеспечивают безопасность нашему приложению, которое теперь будет принимать только те запросы, в которых есть токен доступа. В противном случае запросы будут отклонены с ошибкой HTTP 401 Unauthorized. Например:

curl http://localhost:8080/sse --fail-with-body
#
# Response:
#
# curl: (22) The requested URL returned error: 401

Чтобы использовать наш MCP сервер, нам сперва необходимо получить токен доступа. Мы используем client_credentials, выданные OAuth2, что используется в сценариях “от машины к машине” или “сервисный аккаунт”:

curl -XPOST http://localhost:8080/oauth2/token --data grant_type=client_credentials --user mcp-client:secret
#
# Response:
#
# {"access_token":"<YOUR-ACCESS-TOKEN>","token_type":"Bearer","expires_in":299}%

Копируем значение access_token. Оно начинается с букв "ey". Теперь мы можем использовать этот токен для создания запросов, и они должны быть успешными. Например, используя curl, вы сможете заменить YOUR_ACCESS_TOKEN скопированным выше значением:

curl http://localhost:8080/sse -H"Authorization: Bearer YOUR_ACCESS_TOKEN"
#
# Response:
#
# id:918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0
# event:endpoint
# data:/mcp/message?sessionId=918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0

Можно также использовать токен доступа напрямую в MCP инспекторе, начиная с версии 0.6.0. Просто запустите инспектор и вставьте токен доступа в поле "Authentication > Bearer" в меню слева. Затем нажмите “Connect”: теперь у вас должна появиться возможность отправлять MCP вызовы.

Если вы хотите запустить эти программы самостоятельно, вы можете взять код примера из репозитория spring-ai-examples.

Что дальше?

В нашем примере мы реализовали базовые возможности OAuth2 в MCP сервере.

Очевидный следующий шаг — обновить MCP клиент и позволить ему аутентифицироваться на сервере с использованием OAuth2 authorization_code grant-а вместо client_credentials. При таком сценарии пользователи смогут залогиниться со своими собственными кредами и получить свои пользовательские токены, что позволяет более точно назначать пермишены, например с помощью Roles-Based Access Control (RBAC).

В будущем, мы также посмотрим на внешний сервер авторизации OAuth2 и выпуск токенов с его помощью, используя только возможности сервера ресурсов (OAuth2 Resource Server-а) внутри нашего MCP сервера.


Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.

Теги:
Хабы:
+1
Комментарии0

Публикации

Информация

Сайт
t.me
Дата регистрации
Численность
11–30 человек