Skip to content
ВозможностиДокументацияЦеныПартнёрыPlaygroundFAQ
MCPBest PracticesConfiguration

Безопасность MCP: 10 лучших практик настройки Model Context Protocol

1 минута чтения

Безопасность MCP (Model Context Protocol) почти никогда не попадает в фокус на старте проекта: разработчики подключают сервер в development-режиме через claude mcp add, видят, что tool-вызовы работают, и идут дальше. К моменту, когда AI-агенты выходят в production, дефолтная MCP конфигурация превращается в дыру — wildcard-tools, plaintext-credentials в .mcp.json, неограниченные scopes и процесс с полным доступом к $HOME. Эти MCP best practices собраны как инженерный чек-лист из десяти настроек hardening'а: каждую можно применить за один деплой и проверить одной командой. Это не каталог векторов атак (он есть вотдельной статье про утечку credentials), а конкретный список того, что включить, ограничить и залогировать.

Краткий ответ

Безопасный MCP в production — это десять независимых настроек hardening'а, применяемых по слоям: протокол (минимизация scopes, allowlist tools), изоляция процесса (systemd-sandbox, eBPF shield), защита данных(credential vault, аудит-журнал), логика разрешений (OPA/Rego policy, бюджетный governor) и инфраструктура (provenance/pinning, таймауты и circuit breaker). Каждая практика включается за один деплой и проверяется одной командой — чек-маркером прямо в статье.

Что вы узнаете

  • Почему дефолтный MCP-сервер не годится для production и что именно закрывать.
  • 10 практик hardening'а: scopes, allowlist, sandbox, eBPF, vault, аудит, policy, бюджет, provenance, таймауты.
  • Готовый .mcp.json, systemd-unit и Rego-политика для копирования.
  • Чек-маркер для каждой практики — команда проверки, что настройка реально включена.

10

практик hardening'а MCP для productionСверху вниз по стеку: протокол → ядро ОС → данные → логика → инфраструктура. Каждая проверяется одной командой.

Почему MCP требует hardening

Model Context Protocol стандартизирует, как LLM вызывает внешние инструменты: клиент (Cursor, Claude Code, Copilot) общается с MCP-сервером по stdio или HTTP/SSE, а сервер превращает запрос модели в реальное действие — SQL-запрос, файловую операцию, HTTP-вызов. Архитектура элегантная, но у неё есть три свойства, которые делают дефолт опасным.

Первое — сервер работает с привилегиями пользователя, который его запустил: студенческий MCP-сервер для чтения ./docs имеет тот же доступ к файловой системе, что и ваш SSH-ключ. Второе — инструмент активируется по текстовой инструкции модели, а значит prompt injection напрямую управляет surface area атаки. Третье— гранулярность доступа задаётся реализацией конкретного сервера, и в большинстве из неё нет: либо «всё разрешено», либо «никаких tools».

Это сочетание подтверждается OWASP Top 10 for LLM Applications (LLM06 — чрезмерное агентское действие) и подробно разбирается в гайде по production-деплою Claude Code. Десять MCP security-практик ниже систематически закрывают каждый зазор: от scopes на уровне протокола до eBPF-мониторинга на уровне ядра.

Практика 1: Минимизация scopes

Практика. Каждому MCP-серверу назначать минимальный набор scopes — ровно те ресурсы, которые нужны для его задачи, и ни одним больше.

Почему важно. Scope определяет, к чему tool-сервер может дотянуться: файлы, базы, API-эндпоинты, конкретные таблицы. Чем шире scope, тем больше blast radius при compromise или prompt injection. Сервер, которому нужен только read-only доступ к одной таблицеdocs, не должен видеть pg_shadow или /etc.

.mcp.json
json
# .mcp.json — scopes вместо wildcard
{
"mcpServers": {
"knowledge-base": {
"command": "npx",
"args": ["-y", "@flowlink/mcp-pg"],
"env": {
"DATABASE_URL": "flowlink://ref/docs-db-readonly"
},
"scopes": [
"db:read:public.docs",
"db:read:public.snippets"
],
"denyScopes": ["db:write:*", "fs:*", "shell:*"]
}
}
}

Заметьте паттерн: явные denyScopes поверх позитивного списка. Это защита от будущего — если новая версия сервера запросит расширенные права, они не пройдут молча.

Чек-маркер: ☐ в .mcp.json нет строки "scopes": ["*"] ни у одного сервера.

Практика 2: Allowlist tools вместо wildcard

Практика. Разрешать на уровне хоста только именованные tools, а не весь каталог, который публикует сервер.

Почему важно. Один MCP-сервер может экспортировать десятки tools:read_file, write_file, exec, fetch_url. Дефолтное поведение большинства клиентов — регистрировать все. Allowlist превращает «что умеет сервер» в «что разрешено вызывать модели», и это две разные вещи.

flowlink.config.yaml
yaml
# Хост-конфиг (flowlink.config.yaml)
tools:
allow:
- knowledge-base.search_docs
- knowledge-base.get_snippet
deny:
- "*.exec"
- "*.shell"
- "*.write_*"
requireApproval:
- "*.delete_*"
- "*.drop_*"

Здесь же — правило requireApproval: деструктивные tools блокируются до явного подтверждения человеком. Это продолжение темызащиты от деструктивных команд в Cursor, применённое уже к MCP-интерфейсу.

Чек-маркер:flowlink tools list показывает только те tools, что перечислены в allow.

Практика 3: Изоляция процесса через systemd sandbox

Практика. Запускать каждый MCP-сервер как изолированный systemd-unit с ограничениями на файловую систему, сеть и системные вызовы.

Почему важно. Scopes и allowlist ограничивают логический слой протокола. Но если в сервере RCE-уязвимость, атака уходит ниже — на уровень ОС. systemd даёт declaraтивный sandbox, который работает независимо от корректности приложения.

mcp-knowledge.service
ini
# /etc/systemd/system/mcp-knowledge.service
[Service]
Type=simple
ExecStart=/usr/bin/npx -y @flowlink/mcp-pg
User=mcp-svc
Group=mcp-svc
# Файловая система — только своё и только на чтение остальное
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/mcp-knowledge
# Сеть — только нужный хост
IPAddressAllow=10.0.1.20
RestrictAddressFamilies=AF_INET AF_UNIX
# Системные вызовы — минимальный whitelist
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources @mount
NoNewPrivileges=true
RestrictSUIDSGID=true
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target

Этот же приём рекомендует NIST SP 800-190 (контейнерная безопасность) для любого сервиса, обрабатывающего недоверенный ввод. Для MCP-сервера недоверенный ввод — это, по сути, весь трафик от модели.

Чек-маркер:systemd-analyze security mcp-knowledge.service показывает оценку ≤ 3.0 (из 10, где меньше — безопаснее).

Практика 4: eBPF shield для системных вызовов

Практика. Поверх systemd-seccomp поднять eBPF-политику, которая перехватывает системные вызовы и сетевые соединения на уровне ядра, в runtime.

Почему важно. systemd фильтрует по имени syscall, а eBPF — по контексту: кто, когда, к какому хосту, с каким payload-размером. Это позволяет, например, разрешитьconnect() к базе, но заблокировать исходящие на *.amazonaws.com или любые non-TLS соединения. seccomp статичен; eBPF — runtime-observability и enforcement в одном.

flowlink-shield.yaml
yaml
# flowlink shield policy (YAML)
shield:
enabled: true
target: mcp-knowledge.service
syscalls:
deny: [ptrace, keyctl, bpf, unshare]
network:
egress:
allow:
- cidr: 10.0.1.20/32
port: 5432
deny:
- cidr: 0.0.0.0/0
port: 443 # блокируем exfiltration через HTTPS
on_violation: block_and_alert

FlowLink eBPF Shield работает по модели allow-list egress: по умолчанию исходящий трафик запрещён, и вы явно открываете только нужные destination'ы. Это убивает целый класс атак, где скомпрометированный server exfiltrate'ит данные на внешний endpoint.

Чек-маркер:flowlink shield status mcp-knowledge показывает violations: 0 и egress policy: enforce.

Практика 5: Credential vault вместо plaintext-окружения

Практика. Никогда не класть секреты в env-блок .mcp.jsonнапрямую. Использовать ссылку на vault, которая резолвится только в момент вызова.

Почему важно. Файл .mcp.json попадает в git, в бэкапы, в логи деплоя и в контекст самой модели, если она читает конфиг. Plaintext-токен в env — самая частая причина инцидентов с MCP, и единственная, которую можно устранить за пять минут.

.mcp.json — неправильно
json
# Плохо
"env": { "DATABASE_URL": "postgres://admin:s3cr3t@db:5432/prod" }
.mcp.json — правильно
json
# Хорошо — ссылка на FlowLink Credential Vault
"env": {
"DATABASE_URL": "flowlink://ref/docs-db-readonly"
},
"vault": {
"provider": "flowlink",
"ttlSeconds": 3600,
"leakProtection": true
}

Vault резолвит flowlink://ref/... в реальный DSN только внутри процесса MCP-сервера, ротирует ключи по TTL и помечает их в gitleaks-сканере как known-good, чтобы случайно не поднять ложную тревогу. Подробнее о схеме работы vault — в статье пропять векторов утечки credentials в MCP.

Чек-маркер:grep -rEn "(password|secret|token|AKIA)" .mcp.json возвращает 0 строк.

Практика 6: Аудит-журнал всех tool-вызовов

Практика. Записывать каждый tool-call в append-only журнал: who, what, when, what-args (без секретов), какой результат, сколько времени.

Почему важно. Без журнала инцидент с MCP невозможно расследовать вообще. Вы не узнаете, какой tool вызвала модель, какие аргументы передала, какой файл она в итоге прочитала. Аудит-журнал — это и форензика, и база для алёртов (практика 8), и compliance по ISO 27001 A.12.4 / SOC 2 CC7.2.

flowlink.audit.yaml
yaml
# flowlink audit config
audit:
sink: postgres
table: mcp_tool_calls
fields:
- ts
- session_id
- principal # SPIFFE SVID, не "user"
- tool
- args_hash # sha256, без plaintext секретов
- args_redacted # секреты замаскированы как ***REDACTED***
- result_status
- duration_ms
- policy_decision # allow | deny | prompt
tamperProtection: forward-chaining-hmac

Запись идёт в mcp_tool_calls с HMAC forward-chaining — каждая строка подписана ключом предыдущей, поэтому удалить или изменить запись незаметно нельзя. Это та же техника, что в блокчейне, и она проходит аудит на tamper-evidence. Как агрегировать эти данные в дашборды и алёрты, описано в материале промониторинг активности AI-агентов на сервере.

Чек-маркер:SELECT count(*) FROM mcp_tool_calls WHERE ts > now()-interval '1 hour' > 0 после тестового вызова.

Практика 7: Policy engine на OPA/Rego

Практика. Выносить решения «разрешить/запретить» в декларативную policy на Rego, а не раскидывать if-проверки по коду сервера.

Почему важно. Policy в коде невозможно аудировать, версионировать и быстро менять. OPA (Open Policy Agent) с языком Rego — индустриальный стандарт (CNCF graduated), который отделяет enforcement от бизнес-логики. Вы пишете правило один раз и применяете его и к MCP, и к Kubernetes, и к API-gateway.

mcp.rego
rego
# /etc/flowlink/policy/mcp.rego
package flowlink.mcp
default allow := false
# Разрешить только read-доступ к docs в рабочее время
allow if {
input.tool in {"knowledge-base.search_docs", "knowledge-base.get_snippet"}
input.action == "read"
time.weekday(input.ts) in workdays
time.parse_rfc3339(input.ts) >= time.add(now(), -duration("1h")).__val__
not sensitive_table(input.args)
}
workdays := {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}
sensitive_table(args) if {
re_match("(?i)\\b(users|billing|secrets|pg_shadow)\\b", args.query)
}
# Деструктивные операции — только с явным approval
deny[msg] if {
input.action == "write"
not input.approval
msg := sprintf("write requires approval: %v", [input.tool])
}

Тот же Rego-файл ходит в unit-тесты (opa test mcp.rego mcp_test.rego), в CI и в runtime enforcement. Изменение политики проходит code-review, а не деплой новой версии MCP-сервера.

Чек-маркер:opa check /etc/flowlink/policy выходит без ошибок; flowlink policy test зелёный.

Практика 8: Бюджетный governor для tool-вызовов

Практика. Ставить rate-limit и стоимостный потолок на tool-вызовы, не только на LLM-токены.

Почему важно. Две группы атак на MCP экономят не токены, а ваши API-лимиты и кошелёк: (1) feedback-loop, где модель рекурсивно вызывает дорогой tool (внешний платный API, тяжёлый SQL), (2) resource exhaustion — SELECT * на таблице в 50 млн строк кладёт базу. Governor ставит hard-cap и на то, и на другое.

flowlink.budget.yaml
yaml
# flowlink budget governor
budget:
window: 1h
per_session:
max_tool_calls: 200
max_cost_usd: 5.00 # внешние API-вызосы
per_tool:
"knowledge-base.search_docs":
max_calls_per_minute: 30
max_result_rows: 1000
on_exceed:
action: throttle
alert: "#sec-ai-agents"

Это прямой родственник бюджетного governor'а для LLM-вызовов изсоответствующей статьи — та же механика (скользящее окно, hard/soft limit, throttling вместо молчаливого провала), но применённая к tool-layer.

Чек-маркер: ☐ в Prometheus метрика flowlink_tool_calls_total{status="throttled"} существует (значение может быть 0, метрика должна быть определена).

Практика 9: Подпись и пиннинг MCP-серверов (provenance)

Практика. Пиннинг конкретной версии MCP-сервера и проверка его подписи (SLSA-провенанс) перед запуском. Никаких @latest в production.

Почему важно. Экосистема MCP-серверов — это npm-пакеты и Docker-образы от десятков авторов. Supply-chain-атака (compromised upstream, typosquatting, malicious PR) — реальный вектор: достаточно один раз обновить @example/mcp-db и получить backdoor на всех, кто запускал npx. SLSA + cosign закрывают именно это.

.mcp.json — provenance
json
# Пиннинг по digest и проверка подписи
{
"mcpServers": {
"knowledge-base": {
"command": "npx",
"args": [
"-y",
"@flowlink/mcp-pg@1.4.2",
"--integrity", "sha512-L0gq...8w=="
],
"provenance": {
"verify": true,
"sigstore": true,
"expectedIssuer": "https://token.actions.githubusercontent.com",
"expectedSource": "github.com/flowlink/mcp-pg",
"expectedDigest": "sha256:a1b2c3..."
}
}
}
}

При каждом запуске FlowLink проверяет Sigstore-подпись образа, сравнивает source-uri с ожидаемым и сверяет digest. Любое несовпадение — server не стартует, в audit-журнал летит событие provenance_mismatch. Это уровень защиты, рекомендованный SLSA Build Level 3.

Чек-маркер:flowlink verify --all показывает verified для каждого сервера; ни одного @latest в конфиге.

Практика 10: Таймауты и circuit breaker

Практика. На каждый tool навесить жёсткий таймаут и circuit breaker, который размыкается после N ошибок подряд.

Почему важно. Зависший tool — это не просто медленный ответ. В синхронной модели это заблокированный session, в асинхронной — накапливающиеся connection'ы и падение по OOM. Circuit breaker переводит каскадный сбой в graceful degradation: несколько таймаутов подряд → tool временно отключается → модель получает понятное сообщение вместо зависания.

flowlink.resilience.yaml
yaml
# flowlink resilience config
resilience:
default:
timeout_ms: 5000
retry: { max_attempts: 2, backoff: exponential }
circuitBreaker:
enabled: true
failure_threshold: 5 # 5 ошибок подряд
failure_window: 60s
open_duration: 120s # 2 минуты в открытом состоянии
half_open_probes: 1
per_tool:
"knowledge-base.search_docs":
timeout_ms: 3000
failure_threshold: 3
"external.weather_api":
timeout_ms: 2000
circuitBreaker:
open_duration: 600s # внешний — дольше "отдыхает"

Таймаут и breaker решают и проблему безопасности: длинный зависший запрос — частый признак SSRF-попытки или эксплуатации time-based SQL injection. Быстрый fail = меньше окно атаки.

Чек-маркер: ☐ метрика flowlink_circuit_breaker_state{tool="..."} присутствует; тест с искусственным таймаутом переводит state в open.

Готовый .mcp.json

Ниже — собранный воедино .mcp.json, в котором применены все десять практик. Это отправная точка для production-деплоя: замените имена серверов и resource-refs на свои и прогоните чек-маркеры сверху вниз.

.mcp.json
json
{
"$schema": "https://flowlink.dev/schema/mcp.json",
"mcpServers": {
"knowledge-base": {
"command": "npx",
"args": ["-y", "@flowlink/mcp-pg@1.4.2",
"--integrity", "sha512-L0gq...8w=="],
"env": { "DATABASE_URL": "flowlink://ref/docs-db-readonly",
"LOG_LEVEL": "warn" },
"scopes": ["db:read:public.docs", "db:read:public.snippets"],
"denyScopes": ["db:write:*", "fs:*", "shell:*"],
"vault": { "provider": "flowlink", "ttlSeconds": 3600 },
"provenance": { "verify": true, "sigstore": true,
"expectedSource": "github.com/flowlink/mcp-pg" },
"tools": { "allow": ["search_docs", "get_snippet"] },
"resilience": { "timeout_ms": 3000,
"circuitBreaker": { "failure_threshold": 3,
"open_duration": 120 } }
}
},
"policy": { "engine": "opa", "path": "/etc/flowlink/policy/mcp.rego" },
"budget": { "window": "1h",
"per_session": { "max_tool_calls": 200, "max_cost_usd": 5.00 } },
"audit": { "sink": "postgres", "tamperProtection": "forward-chaining-hmac" },
"shield": { "enabled": true, "egress": "allow-list" }
}

Сводный чек-лист: 10 практик MCP security

Сводный чек-лист: 10 практик MCP security — что закрывает каждая настройка и как её проверить
#ПрактикаЧто закрываетПроверка
1Минимизация scopesЧрезмерный доступ к даннымНет "*" в scopes
2Allowlist toolsНеавторизованные действия моделиflowlink tools list = allow
3systemd sandboxRCE на уровне ОСsecurity score ≤ 3.0
4eBPF shieldExfiltration и lateral movementshield status: enforce
5Credential vaultPlaintext-утечки секретовgrep по конфигу пуст
6Аудит-журналНевозможность форензикиСтроки в mcp_tool_calls
7OPA/Rego policyЛогика разрешений в кодеopa check чист
8Бюджетный governorResource exhaustion, cost-bombМетрика throttled существует
9Provenance / pinningSupply-chain-атакиflowlink verify --all = ok
10Таймауты + breakerКаскадные сбои, SSRF-windowstate ∈ open при тесте
Стек защиты MCP по слоям
  1. Протокол
  2. Ядро ОС
  3. Данные
  4. Логика
  5. Инфраструктура

Десять настроек покрывают стек целиком: протокол (scopes, allowlist) → ядро ОС (systemd, eBPF) → данные (vault, аудит) → логика (policy, budget) → инфраструктура (provenance, resilience). Применяйте их сверху вниз — так каждая следующая MCP конфигурацияопирается на уже включённую предыдущую, и к концу прохода вы получаете воспроизводимый, аудируемый деплой по этим MCP best practices, а не набор разрозненных твиков.

Порядок внедрения 10 практик MCP security

Реалистичный четырёхфазный план — от быстрых побед на уровне протокола до supply-chain и устойчивости.

  1. Фаза 1 — Протокол (практики 1–2)

    Начните с .mcp.json и хост-конфига: пропишите минимальные scopes/denyScopes и allowlist tools вместо wildcard. Это быстрая победа, которая сужает blast radius ещё до любого изменения инфраструктуры.

  2. Фаза 2 — Изоляция и ядро ОС (практики 3–4)

    Переведите MCP-серверы в выделенные systemd-unit'ы с sandbox-директивами и поднимите FlowLink eBPF shield с allow-list egress. Теперь даже RCE в сервере не даёт доступа за пределы sandbox.

  3. Фаза 3 — Данные и логика (практики 5–8)

    Подключите credential vault, включите append-only аудит-журнал с HMAC forward-chaining, вынесите разрешения в OPA/Rego и поставьте бюджетный governor на tool-вызовы. Эти четыре настройки дают форензику, compliance и защиту от cost-bomb.

  4. Фаза 4 — Целостность и устойчивость (практики 9–10)

    Завершите hardening пиннингом версий с SLSA/Sigstore provenance и навесьте таймауты с circuit breaker на каждый tool. Теперь деплой защищён и от supply-chain-атак, и от каскадных сбоев.

Чек-лист hardening'а: стоит ли внедрять все 10 практик

Плюсы

  • Покрытие всего стека: от протокола (scopes) до ядра ОС (eBPF) и инфраструктуры (provenance)
  • Каждая настройка проверяется одной командой — воспроизводимый, аудируемый деплой
  • Слои независимы: sandbox работает, даже если в приложении найдётся RCE
  • Аудит-журнал и OPA/Rego дают форензику и compliance (ISO 27001 A.12.4, SOC 2 CC7.2)

Минусы

  • Эксплуатационная сложность: systemd, eBPF, OPA и vault нужно поддерживать вместе
  • Требуется экспертиза в Linux-security и supply-chain (SLSA, Sigstore, cosign)
  • Часть практик (eBPF shield, provenance-верификация) добавляет накладные расходы на запуск
  • Начальный порог входа выше, чем у дефолтного npx-запуска без ограничений

Для собственных MCP-серверов

Чек-лист — это минимум для production. Для собственных MCP-серверов добавьте fuzzing tool-интерфейса и threat-modeling по STRIDE: без них пункт 3 (sandbox) остаётся единственной линией обороны.

Часто задаваемые вопросы

Что такое MCP security и зачем нужен hardening Model Context Protocol?

MCP (Model Context Protocol) стандартизует, как LLM-клиент (Cursor, Claude Code, Copilot) вызывает внешние инструменты через MCP-сервер. Дефолтная конфигурация даёт серверу привилегии запустившего пользователя, wildcard-tools и plaintext-секреты в .mcp.json, поэтому hardening сужает blast radius: от минимизации scopes на уровне протокола до eBPF-мониторинга на уровне ядра.

Какие 10 практик входят в чек-лист MCP security?

(1) минимизация scopes, (2) allowlist tools, (3) systemd-sandbox, (4) eBPF shield, (5) credential vault, (6) аудит-журнал tool-вызовов, (7) OPA/Rego policy, (8) бюджетный governor, (9) подпись и пиннинг серверов (SLSA-provenance), (10) таймауты и circuit breaker. Они покрывают пять слоёв: протокол → ядро ОС → данные → логику → инфраструктуру.

Чем scopes отличаются от allowlist tools?

Это два разных слоя. Scopes описывают, к каким ресурсам сервер может дотянуться (db:read:public.docs, fs:*), а allowlist tools — какие инструменты модели разрешено вызывать независимо от того, что публикует сервер. Scopes ограничивают сервер, allowlist ограничивает модель.

Обязательны ли все 10 практик для production?

Минимальный набор — scopes, allowlist, credential vault, аудит-журнал и таймауты: они закрывают самые частые инциденты за один деплой. eBPF shield, systemd-sandbox, OPA/Rego, бюджетный governor и SLSA-provenance рекомендованы для зрелых деплоев, где есть compliance-требования (ISO 27001, SOC 2) и реальный риск supply-chain-атак.

Даёт ли статья готовый конфиг для копирования?

Да. В статье есть готовый .mcp.json со всеми десятью настройками, отдельный systemd-unit mcp-knowledge.service с sandbox-директивами и Rego-политика mcp.rego для OPA. Замените имена серверов и resource-refs на свои и прогоните чек-маркеры.

Как проверить, что каждая настройка реально включена?

У каждой практики есть чек-маркер — одна команда. Например, flowlink tools list для allowlist, systemd-analyze security для sandbox (цель ≤ 3.0), opa check для политики, flowlink verify --allдля provenance. Если все чек-маркеры проходят — деплой соответствует чек-листу.

Готовы защитить свои AI-агенты?

Начните с бесплатного аудита безопасности ваших AI-инструментов.

Получить бесплатный аудит