Sicurezza e autenticazione di MCP
Aggiunga l'autenticazione al server MCP utilizzando token OAuth 2.0, implementi la validazione degli input per prevenire gli attacchi di injection e applichi il principio del privilegio minimo alle autorizzazioni degli strumenti.
Sicurezza e autenticazione di MCP è una lezione AI Engineering Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento AI Engineering Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso AI Engineering Academy include 4 lezioni in totale.
Perché la sicurezza MCP è importante
Un server MCP è un punto di accesso ai Suoi sistemi. Senza una sicurezza adeguata, un client IA compromesso o un prompt malevolo potrebbe leggere dati sensibili, attivare operazioni distruttive o esfiltrare informazioni attraverso il canale delle chiamate agli strumenti. La sicurezza dei server MCP deve adottare una difesa in profondità: autenticazione a livello di trasporto, autorizzazione a livello di strumento e convalida degli input a ogni chiamata.
Sicurezza dei server locali e remoti
Il trasporto stdio, usato da Claude Desktop, offre una sicurezza intrinseca: il server viene eseguito come processo locale ed è accessibile solo dall'utente che lo ha avviato. I server MCP esposti in rete tramite HTTP/SSE sono soggetti all'intera gamma delle minacce alla sicurezza web: bypass dell'autenticazione, attacchi injection e accessi non autorizzati. I requisiti di sicurezza cambiano radicalmente in base alla modalità di distribuzione.
- stdio locale: si considera attendibile l'utente locale; ci si concentra sulla convalida degli input
- HTTP/SSE remoto: autenticazione completa, TLS, limitazione della frequenza e sanificazione degli input
Autenticazione con chiave API per server remoti
Il metodo più semplice per autenticare i server MCP remoti consiste nel convalidare una chiave API tramite un'intestazione HTTP. Controlli l'intestazione Authorization: Bearer <token> su ogni richiesta in ingresso e rifiuti le richieste non autenticate con HTTP 401. Memorizzi le chiavi API valide in un database insieme ai metadati dell'utente, così potrà revocare singole chiavi.
# 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 per server MCP aziendali
Per le distribuzioni aziendali, utilizzi OAuth 2.0 affinché gli utenti possano autenticarsi tramite il provider di identità aziendale, come Okta, Azure AD o Google Workspace. Il client MCP ottiene un token di accesso OAuth, che include nelle richieste di chiamata agli strumenti. Il server convalida la firma del token rispetto alle chiavi pubbliche del provider di identità usando python-jose o 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}')Autorizzazione basata sugli ambiti
Non tutti gli strumenti MCP devono essere disponibili a tutti gli utenti. Utilizzi gli ambiti OAuth o le attestazioni dei ruoli nel token JWT per determinare quali strumenti l'utente autenticato può chiamare. Verifichi l'autorizzazione all'inizio di ogni esecuzione dello strumento, prima di effettuare qualsiasi chiamata al database o a un'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 toolConvalida degli input e prevenzione delle injection
Tutti gli input degli strumenti sono in ultima analisi stringhe generate da un LLM: li tratti come non attendibili. Convalidi ogni input rispetto ai tipi e ai modelli previsti prima di utilizzarlo. In particolare, protegga il sistema da: SQL injection, usando query parametrizzate e mai SQL interpolato tramite stringhe; command injection, non passando mai input dell'utente a comandi shell; e path traversal, normalizzando e convalidando i percorsi dei file.
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 valueLimitazione della frequenza delle chiamate agli strumenti
Un agente LLM in un ciclo potrebbe chiamare strumenti costosi centinaia di volte al minuto, esaurendo le connessioni al database, le quote delle API di terze parti o il budget di calcolo. Implementi limiti di frequenza per utente usando un algoritmo token bucket in Redis. Rifiuti le chiamate agli strumenti che superano il limite con un errore descrittivo, affinché l'agente sappia di dover attendere.
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.'
)Principio del privilegio minimo
Applichi il principio del privilegio minimo a ogni livello del server MCP. L'utente del database deve avere accesso esclusivamente in lettura alle tabelle necessarie al server. Il processo del server deve essere eseguito da un utente del sistema operativo non root. Gli strumenti devono richiedere solo le autorizzazioni necessarie. Le chiavi API devono avere l'ambito minimo richiesto dal loro scopo. Ogni autorizzazione negata rappresenta un potenziale attacco che non potrà andare a buon fine.
-- 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 permissionsSicurezza TLS e del trasporto
I server MCP remoti devono usare TLS per proteggere i dati in transito. Configuri il server affinché accetti esclusivamente connessioni HTTPS. In produzione, utilizzi un reverse proxy, come nginx o Caddy, per gestire la terminazione TLS e mantenere aggiornati i certificati con il rinnovo automatico, ad esempio Let's Encrypt tramite Certbot o il supporto ACME integrato di 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 tramite le risorse MCP
Esiste un vettore di attacco più sottile: se il server MCP legge contenuti da fonti esterne, come pagine web, file caricati dagli utenti o database non attendibili, e li restituisce come risultato di uno strumento, un attaccante potrebbe incorporare istruzioni ostili in tali contenuti. Il modello potrebbe obbedire alle istruzioni nascoste nei dati recuperati: si tratta di prompt injection indiretta. Sanifichi i contenuti recuperati e non restituisca mai testo grezzo non attendibile direttamente come output di uno strumento.
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 stuffingAudit e monitoraggio della sicurezza
Registri tutti gli eventi rilevanti per la sicurezza: autenticazioni riuscite e fallite, violazioni dei limiti di frequenza, rifiuti di autorizzazione, errori di convalida e schemi di accesso insoliti. Configuri avvisi per: molteplici tentativi di autenticazione falliti (forza bruta), un singolo utente che richiama rapidamente strumenti distruttivi e qualsiasi chiamata a uno strumento con input estremamente voluminosi. Esamini regolarmente i log di audit e automatizzi il rilevamento delle anomalie.
Verifica rapida
Verifichi la Sua comprensione dei concetti di sicurezza e autenticazione di MCP.
Riepilogo della lezione
In questa lezione ha imparato che: i server MCP remoti richiedono l'autenticazione OAuth 2.0 o tramite chiave API per ogni richiesta, l'autorizzazione basata sugli ambiti stabilisce quali strumenti può chiamare ogni utente autenticato e tutti gli input degli strumenti devono essere convalidati per prevenire attacchi di injection e attraversamento dei percorsi. Questo conclude il modulo MCP: ora esploreremo strategie avanzate di chunking per il recupero RAG ad alta precisione.
Domande Frequenti
La lezione «Sicurezza e autenticazione di MCP» è gratuita?
Sì — il testo completo di «Sicurezza e autenticazione di MCP» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso AI Engineering Academy, passa a CoddyKit PRO. Il corso AI Engineering Academy include 4 lezioni in totale.
Cosa imparerò in «Sicurezza e autenticazione di MCP»?
Aggiunga l'autenticazione al server MCP utilizzando token OAuth 2.0, implementi la validazione degli input per prevenire gli attacchi di injection e applichi il principio del privilegio minimo alle a… Eserciti AI Engineering Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare AI Engineering Academy?
Non è richiesta alcuna esperienza precedente. AI Engineering Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Sicurezza e autenticazione di MCP»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione AI Engineering Academy?
Sì. Ogni lezione AI Engineering Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Che cos'è MCP e perché è importante
- Creare il primo server MCP
- Esporre risorse del database tramite MCP
- Sicurezza e autenticazione di MCP