Bezpieczeństwo i uwierzytelnianie MCP
Dodaj uwierzytelnianie do serwera MCP za pomocą tokenów OAuth 2.0, zastosuj walidację danych wejściowych, aby zapobiegać atakom typu injection, oraz zasadę najmniejszych uprawnień dla uprawnień narzędzi.
Bezpieczeństwo i uwierzytelnianie MCP to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Dlaczego bezpieczeństwo MCP ma znaczenie
Serwer MCP jest bramą do Państwa systemów. Bez odpowiednich zabezpieczeń przejęty klient AI lub złośliwy prompt może odczytać poufne dane, uruchomić destrukcyjne operacje albo wyprowadzić informacje przez kanał wywołań narzędzi. Bezpieczeństwo serwerów MCP musi opierać się na ochronie warstwowej: uwierzytelnianiu na poziomie warstwy transportowej, autoryzacji na poziomie narzędzi oraz walidacji danych wejściowych przy każdym wywołaniu.
Bezpieczeństwo serwera lokalnego a zdalnego
Transport stdio (używany przez Claude Desktop) zapewnia wbudowane bezpieczeństwo: serwer działa jako proces lokalny i jest dostępny wyłącznie dla użytkownika, który go uruchomił. Serwery MCP udostępnione w sieci za pomocą HTTP/SSE są narażone na pełen zakres zagrożeń związanych z bezpieczeństwem sieci: obejście uwierzytelniania, ataki typu injection i nieautoryzowany dostęp. Wymagania dotyczące bezpieczeństwa znacznie różnią się w zależności od trybu wdrożenia.
- Lokalne stdio: zaufaj lokalnemu użytkownikowi; skup się na walidacji danych wejściowych
- Zdalne HTTP/SSE: pełne uwierzytelnianie, TLS, ograniczanie liczby żądań, oczyszczanie danych wejściowych
Uwierzytelnianie za pomocą klucza API dla serwerów zdalnych
Najprostsze uwierzytelnianie zdalnych serwerów MCP polega na sprawdzaniu klucza API w nagłówku HTTP. Sprawdzaj nagłówek Authorization: Bearer <token> przy każdym przychodzącym żądaniu i odrzucaj nieuwierzytelnione żądania, zwracając HTTP 401. Przechowuj prawidłowe klucze API w bazie danych wraz z metadanymi użytkownika, aby móc unieważniać poszczególne klucze.
# For HTTP/SSE MCP servers using FastAPI or similar:
from fastapi import FastAPI, HTTPException, Depends, Header
from typing import Optional
import secrets
app_http = FastAPI()
# In production: store in database with user_id, created_at, last_used
VALID_KEYS = {'sk-mcp-abc123': {'user': 'alice', 'scopes': ['read']},
'sk-mcp-def456': {'user': 'bob', 'scopes': ['read', 'write']}}
async def verify_api_key(authorization: Optional[str] = Header(None)) -> dict:
if not authorization or not authorization.startswith('Bearer '):
raise HTTPException(status_code=401, detail='Missing API key')
key = authorization.removeprefix('Bearer ')
if key not in VALID_KEYS:
raise HTTPException(status_code=401, detail='Invalid API key')
return VALID_KEYS[key] # Returns user context
# Use in route handlers:
# @app_http.get('/sse')
# async def sse_endpoint(user=Depends(verify_api_key)):OAuth 2.0 dla serwerów MCP w przedsiębiorstwach
W przypadku wdrożeń korporacyjnych używaj OAuth 2.0, aby użytkownicy uwierzytelniali się za pomocą firmowego dostawcy tożsamości (Okta, Azure AD, Google Workspace). Klient MCP uzyskuje token dostępu OAuth i dołącza go do żądań wywołania narzędzi. Serwer weryfikuje podpis tokenu względem kluczy publicznych dostawcy tożsamości za pomocą python-jose lub authlib.
from jose import jwt, JWTError
import httpx
AUTH_DOMAIN = 'your-tenant.auth0.com'
AUDIENCE = 'https://api.your-mcp-server.com'
async def get_jwks():
async with httpx.AsyncClient() as client:
resp = await client.get(f'https://{AUTH_DOMAIN}/.well-known/jwks.json')
return resp.json()
async def verify_oauth_token(token: str) -> dict:
jwks = await get_jwks()
try:
payload = jwt.decode(
token,
jwks,
algorithms=['RS256'],
audience=AUDIENCE,
issuer=f'https://{AUTH_DOMAIN}/'
)
return payload # Contains sub (user ID), scope, exp, etc.
except JWTError as e:
raise ValueError(f'Invalid token: {e}')Autoryzacja oparta na zakresach
Nie wszystkie narzędzia MCP powinny być dostępne dla wszystkich użytkowników. Użyj zakresów OAuth lub deklaracji ról w tokenie JWT, aby określić, które narzędzia może wywoływać uwierzytelniony użytkownik. Sprawdzaj autoryzację na początku każdego wykonania narzędzia, zanim zostanie wykonane jakiekolwiek wywołanie bazy danych lub API.
TOOL_REQUIRED_SCOPES = {
'list_products': ['read:products'],
'search_products': ['read:products'],
'create_order': ['write:orders'],
'delete_order': ['admin:orders']
}
def check_authorization(tool_name: str, token_payload: dict):
'''Raise ValueError if user lacks required scope for the tool.'''
required = TOOL_REQUIRED_SCOPES.get(tool_name, [])
if not required:
return # No scope required
user_scopes = set(token_payload.get('scope', '').split())
missing = [s for s in required if s not in user_scopes]
if missing:
raise ValueError(
f'Access denied. Tool "{tool_name}" requires scopes: {missing}. '
f'Your token has: {list(user_scopes)}'
)
# In call_tool handler:
# check_authorization(name, current_user_token)
# ... then execute the toolWalidacja danych wejściowych i zapobieganie atakom injection
Wszystkie dane wejściowe narzędzi są ostatecznie ciągami znaków wygenerowanymi przez LLM — traktuj je jako niezaufane. Przed użyciem sprawdzaj każde dane wejściowe względem oczekiwanych typów i wzorców. W szczególności chroń się przed: SQL injection (używaj parametryzowanych zapytań, nigdy SQL-a tworzonego przez interpolację ciągów), command injection (nigdy nie przekazuj danych użytkownika do poleceń powłoki) oraz path traversal (normalizuj i sprawdzaj ścieżki plików).
import re
from pathlib import Path
BASE_DATA_DIR = Path('/data/mcp-files')
def safe_file_path(user_input: str) -> Path:
'''Validate and normalize a file path to prevent traversal attacks.'''
# Remove any path traversal sequences
clean = re.sub(r'\.\./', '', user_input)
clean = re.sub(r'\.\.\\\\', '', clean)
path = (BASE_DATA_DIR / clean).resolve()
# Ensure the resolved path is still within the allowed base directory
if not str(path).startswith(str(BASE_DATA_DIR)):
raise ValueError(f'Path traversal detected: {user_input}')
return path
def safe_identifier(value: str) -> str:
'''Validate a database identifier (table/column name).'''
if not re.match(r'^[a-z_][a-z0-9_]{0,63}$', value, re.IGNORECASE):
raise ValueError(f'Invalid identifier: {value}')
return valueOgraniczanie liczby wywołań narzędzi
Agent LLM działający w pętli może wywołać kosztowne narzędzia setki razy na minutę, wyczerpując pulę połączeń z bazą danych, limity zewnętrznych API lub budżet obliczeniowy. Zaimplementuj limity dla poszczególnych użytkowników, używając algorytmu token bucket w Redisie. Odrzucaj wywołania narzędzi przekraczające limit i zwracaj opisowy błąd, aby agent wiedział, że powinien poczekać.
import redis
import time
r = redis.Redis.from_url('redis://localhost:6379')
def check_rate_limit(user_id: str, tool_name: str, limit: int = 60, window: int = 60) -> None:
'''Allow at most `limit` calls per `window` seconds per user per tool.'''
key = f'rate:{user_id}:{tool_name}'
pipe = r.pipeline()
pipe.incr(key)
pipe.expire(key, window)
count, _ = pipe.execute()
if count > limit:
retry_after = r.ttl(key)
raise ValueError(
f'Rate limit exceeded for {tool_name}. '
f'Limit: {limit} calls/{window}s. '
f'Retry after {retry_after} seconds.'
)Zasada najmniejszych uprawnień
Stosuj zasadę najmniejszych uprawnień na każdej warstwie serwera MCP. Użytkownik bazy danych powinien mieć uprawnienia wyłącznie SELECT do tabel wymaganych przez serwer. Proces serwera powinien działać jako użytkownik systemu operacyjnego inny niż root. Narzędzia powinny żądać tylko potrzebnych uprawnień. Klucze API powinny mieć minimalny zakres wymagany do danego zastosowania. Każde odebrane uprawnienie to potencjalny atak, który nie może się powieść.
-- PostgreSQL: Create a dedicated read-only database user for your MCP server
CREATE ROLE mcp_reader LOGIN PASSWORD 'strong_random_password';
-- Grant SELECT on only the tables the server needs
GRANT SELECT ON products, categories, public_content TO mcp_reader;
-- Explicitly deny access to sensitive tables
REVOKE ALL ON users, api_keys, payment_methods FROM mcp_reader;
-- Never grant: INSERT, UPDATE, DELETE, TRUNCATE, or DDL permissionsTLS i bezpieczeństwo transportu
Zdalne serwery MCP muszą używać TLS do ochrony danych podczas przesyłania. Skonfiguruj serwer tak, aby akceptował wyłącznie połączenia HTTPS. W środowisku produkcyjnym użyj odwrotnego serwera proxy (nginx, Caddy) do obsługi terminacji TLS i aktualizowania certyfikatów za pomocą automatycznego odnawiania (Let's Encrypt przez Certbot lub wbudowana obsługa ACME w Caddy).
# Example Caddyfile for TLS-terminating MCP server at a subdomain:
#
# mcp.yourcompany.com {
# reverse_proxy localhost:8080
# encode gzip
# tls internal # Use Let's Encrypt in production
# header {
# Strict-Transport-Security 'max-age=31536000; includeSubDomains'
# X-Content-Type-Options nosniff
# X-Frame-Options DENY
# }
# }Prompt injection za pośrednictwem zasobów MCP
Istnieje subtelny wektor ataku: jeśli serwer MCP odczytuje treści ze źródeł zewnętrznych (stron internetowych, plików przesłanych przez użytkowników, niezaufanych baz danych) i zwraca je jako wynik narzędzia, napastnik może umieścić w tych treściach złośliwe instrukcje. Model może wykonać instrukcje ukryte w pobranych danych — jest to pośredni prompt injection. Oczyszczaj pobrane treści i nigdy nie zwracaj bezpośrednio surowego, niezaufanego tekstu jako wyniku narzędzia.
import re
def sanitize_for_mcp_output(text: str) -> str:
'''Remove patterns that look like instructions to the LLM.'''
# Remove common injection patterns
dangerous_patterns = [
r'ignore previous instructions',
r'ignore all prior instructions',
r'system:',
r'<\|.*?\|>', # Special tokens
r'\[INST\]',
r'<s>',
]
for pattern in dangerous_patterns:
text = re.sub(pattern, '[FILTERED]', text, flags=re.IGNORECASE)
return text[:10000] # Also cap length to prevent context stuffingAudytowanie i monitorowanie bezpieczeństwa
Rejestruj wszystkie zdarzenia istotne z punktu widzenia bezpieczeństwa: pomyślne i nieudane uwierzytelnienia, naruszenia limitów częstotliwości, odmowy autoryzacji, błędy walidacji oraz nietypowe wzorce dostępu. Skonfiguruj alerty dotyczące: wielu nieudanych prób uwierzytelnienia (brute force), sytuacji, w której jeden użytkownik szybko wywołuje narzędzia destrukcyjne, oraz każdego wywołania narzędzia z wyjątkowo dużymi danymi wejściowymi. Regularnie przeglądaj dzienniki audytowe i zautomatyzuj wykrywanie anomalii.
Szybki test
Sprawdź swoją wiedzę na temat bezpieczeństwa i uwierzytelniania w MCP.
Podsumowanie lekcji
W tej lekcji nauczyłeś się, że: zdalne serwery MCP wymagają uwierzytelniania OAuth 2.0 lub za pomocą klucza API przy każdym żądaniu, autoryzacja oparta na zakresach określa, które narzędzia może wywoływać każdy uwierzytelniony użytkownik oraz wszystkie dane wejściowe narzędzi muszą być walidowane, aby zapobiegać atakom typu injection i path traversal. To kończy moduł MCP — teraz zajmiemy się zaawansowanymi strategiami dzielenia na fragmenty na potrzeby precyzyjnego wyszukiwania RAG.
Często zadawane pytania
Czy lekcja „Bezpieczeństwo i uwierzytelnianie MCP” jest bezpłatna?
Tak — pełny tekst „Bezpieczeństwo i uwierzytelnianie MCP” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Bezpieczeństwo i uwierzytelnianie MCP”?
Dodaj uwierzytelnianie do serwera MCP za pomocą tokenów OAuth 2.0, zastosuj walidację danych wejściowych, aby zapobiegać atakom typu injection, oraz zasadę najmniejszych uprawnień dla uprawnień narzę… Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?
Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Bezpieczeństwo i uwierzytelnianie MCP”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?
Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Czym jest MCP i dlaczego ma znaczenie
- Budowanie pierwszego serwera MCP
- Udostępnianie zasobów bazy danych przez MCP
- Bezpieczeństwo i uwierzytelnianie MCP