Zabezpieczanie dostępu agentów do narzędzi
Zastosuj zasadę najmniejszych uprawnień do uprawnień narzędzi agentów, wprowadź etapy potwierdzenia przed destrukcyjnymi działaniami i audytuj dzienniki działań agentów w celu wykrywania anomalii.
Zabezpieczanie dostępu agentów do narzędzi to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 3 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.
Problem bezpieczeństwa dostępu agentów do narzędzi
Udostępniając narzędzie agentowi AI, dają mu Państwo możliwość podejmowania działań w świecie rzeczywistym. Narzędzie, które wysyła wiadomości e-mail, wykonuje zapytania SQL, wywołuje API płatności lub modyfikuje pliki, może wyrządzić poważne szkody, jeśli agent zostanie przejęty w wyniku prompt injection albo po prostu popełni błąd. Zabezpieczanie dostępu agentów do narzędzi oznacza projektowanie warstwy narzędzi tak, aby szkody wynikające z użycia dowolnego narzędzia były ograniczone, możliwe do prześledzenia i — jeśli to możliwe — odwracalne.
Zasada najmniejszych uprawnień
Należy stosować zasadę najmniejszych uprawnień do każdego narzędzia: agent powinien otrzymać minimalny dostęp niezbędny do wykonania powierzonego zadania i nic ponadto. Jeśli agent musi odczytywać dane klientów, należy udostępnić mu połączenie z bazą danych tylko do odczytu — a nie pełne połączenie administratora używane do celów konserwacyjnych. Jeśli wysyła powiadomienia, jego klucz API powinien być ograniczony wyłącznie do punktu końcowego obsługującego powiadomienia. Najmniejsze uprawnienia ograniczają zasięg każdego incydentu bezpieczeństwa.
from enum import Enum
from dataclasses import dataclass
class Permission(Enum):
READ_CUSTOMER_PROFILE = 'read_customer_profile'
SEND_NOTIFICATION = 'send_notification'
READ_ORDER_HISTORY = 'read_order_history'
WRITE_CUSTOMER_PROFILE = 'write_customer_profile' # higher privilege
PROCESS_REFUND = 'process_refund' # highest risk
@dataclass
class AgentIdentity:
agent_id: str
allowed_permissions: set[Permission]
# Support chat agent: read-only + send notification only
SUPPORT_AGENT = AgentIdentity(
agent_id='support-agent-v1',
allowed_permissions={
Permission.READ_CUSTOMER_PROFILE,
Permission.READ_ORDER_HISTORY,
Permission.SEND_NOTIFICATION # can notify, but NOT write or refund
}
)
# NOT: give every agent all permissions for convenienceWykonywanie narzędzi kontrolowane uprawnieniami
Najmniejsze uprawnienia należy egzekwować na poziomie wykonywania, a nie tylko na etapie projektowania. Każde wywołanie narzędzia musi przejść przez sprawdzenie uprawnień, które potwierdza, że wywołujący agent ma wymagane uprawnienie do wykonania konkretnej czynności. Agent ani prompt injection nie mogą ominąć tego mechanizmu, ponieważ jest on wymuszany w kodzie, a nie w promptcie LLM.
class ToolGateway:
def __init__(self, agent: AgentIdentity):
self.agent = agent
self.audit_log = []
def execute_tool(self, tool_name: str, required_permission: Permission, tool_fn, **kwargs) -> dict:
# Permission check - enforced in code, not in the LLM prompt
if required_permission not in self.agent.allowed_permissions:
self.log_denied(tool_name, required_permission, kwargs)
raise PermissionError(
f'Agent {self.agent.agent_id} does not have permission: {required_permission.value}'
)
# Execute tool
result = tool_fn(**kwargs)
self.log_allowed(tool_name, kwargs, result)
return result
def log_denied(self, tool: str, permission: Permission, args: dict):
entry = {'type': 'DENIED', 'agent': self.agent.agent_id, 'tool': tool, 'permission': permission.value, 'args': args}
self.audit_log.append(entry)
print(f'SECURITY: Permission denied - {entry}')
def log_allowed(self, tool: str, args: dict, result):
entry = {'type': 'ALLOWED', 'agent': self.agent.agent_id, 'tool': tool, 'args': args}
self.audit_log.append(entry)
gateway = ToolGateway(SUPPORT_AGENT)
# This will succeed (agent has READ permission)
gateway.execute_tool('read_profile', Permission.READ_CUSTOMER_PROFILE, read_customer_profile, user_id='123')
# This will raise PermissionError (agent lacks PROCESS_REFUND permission)
gateway.execute_tool('process_refund', Permission.PROCESS_REFUND, process_refund, order_id='456', amount=50.00)Potwierdzenia przed wykonaniem destrukcyjnych działań
Niektóre działania są nieodwracalne lub wiążą się z dużym ryzykiem: usuwanie rekordów, wysyłanie masowych wiadomości e-mail czy realizowanie transakcji finansowych. Przed wykonaniem takiego działania przez agenta należy wymagać wyraźnego potwierdzenia człowieka. Agent proponuje działanie (co chce zrobić i dlaczego), człowiek je zatwierdza lub odrzuca, a dopiero potem następuje wykonanie. Ta bramka potwierdzenia jest najskuteczniejszą pojedynczą ochroną przed błędami agenta i nadużyciami wynikającymi z injection.
HIGH_RISK_ACTIONS = {
'delete_customer_record',
'send_bulk_email',
'process_refund_over_100',
'deploy_code',
'revoke_user_access'
}
def execute_with_confirmation(tool_name: str, tool_args: dict, agent_reasoning: str) -> dict:
if tool_name in HIGH_RISK_ACTIONS:
# Pause and request human approval
approval_request = {
'action': tool_name,
'arguments': tool_args,
'agent_reasoning': agent_reasoning,
'risk_level': 'HIGH'
}
approval = request_human_approval(approval_request) # blocks until human responds
if not approval.approved:
return {'status': 'rejected', 'reason': approval.rejection_reason}
# Log the approval for audit trail
log_approval(tool_name, tool_args, approved_by=approval.approver_id)
# Execute only after confirmation
return execute_tool(tool_name, **tool_args)Zakres narzędzi: granice czasu, użytkownika i danych
Oprócz typów uprawnień należy ograniczać dostęp do narzędzi w trzech wymiarach. Granice czasowe: klucze API lub tokeny wygasające po zakończeniu sesji agenta. Granice użytkownika: agent pomagający użytkownikowi A nigdy nie powinien uzyskiwać dostępu do danych użytkownika B, nawet jeśli agent otrzyma takie polecenie. Granice danych: agent obsługi klienta powinien mieć dostęp wyłącznie do danych klienta, któremu aktualnie pomaga, a nie do danych wszystkich klientów. Granice te należy implementować w narzędziach, a nie w promptach agentów.
class ScopedCustomerTool:
def __init__(self, current_user_id: str, session_token: str):
self.user_id = current_user_id # agent can only access THIS user's data
self.token = session_token # expires at end of session
def get_customer_profile(self) -> dict:
# Hardcoded to current user - agent cannot change this via prompt
return db.query(
'SELECT * FROM customers WHERE id = %s',
(self.user_id,) # parameterized, always this user's ID only
)
def get_order_history(self, limit: int = 10) -> list:
# Even if the agent says 'get orders for user 999', it gets self.user_id
return db.query(
'SELECT * FROM orders WHERE customer_id = %s ORDER BY date DESC LIMIT %s',
(self.user_id, min(limit, 50)) # cap limit too
)
# Inject scoped tool into agent - cannot be overridden by prompt
def create_support_agent(user_id: str, session_token: str):
scoped_tools = ScopedCustomerTool(user_id, session_token)
return AgentExecutor(llm=llm, tools=[scoped_tools.get_customer_profile, scoped_tools.get_order_history])Walidacja danych wejściowych argumentów narzędzi
Agenci generują argumenty narzędzi jako tekst. Przed wykonaniem dowolnego narzędzia należy zwalidować wszystkie argumenty względem ścisłego schematu. Zapobiega to: atakom SQL injection przeprowadzanym za pomocą parametrów narzędzi, atakom typu path traversal (agent przekazujący '../../../etc/passwd' jako ścieżkę pliku), atakom SSRF (agent przekazujący adres URL wewnętrznej usługi jako parametr „remote URL”) oraz przepełnieniom liczb całkowitych lub wartościom spoza dozwolonego zakresu, które mogłyby powodować nieoczekiwane działanie.
from pydantic import BaseModel, validator, constr, confloat
import re
class SendEmailArgs(BaseModel):
to: str
subject: constr(max_length=200)
body: constr(max_length=10000)
@validator('to')
def must_be_company_email(cls, v):
if not re.match(r'^[^@]+@(?:yourcorp\.com|partner\.com)$', v):
raise ValueError('Email must be sent to yourcorp.com or partner.com domains only')
return v
class ReadFileArgs(BaseModel):
filename: constr(pattern=r'^[a-zA-Z0-9_\-\.]+$') # alphanumeric only, no path traversal
@validator('filename')
def no_parent_directory(cls, v):
if '..' in v or '/' in v or '\\' in v:
raise ValueError('Path traversal detected')
return v
# Validate before execution
def validated_send_email(args_dict: dict) -> dict:
args = SendEmailArgs(**args_dict) # raises ValueError on invalid input
return send_email(args.to, args.subject, args.body)Niemodyfikowalne logowanie audytowe
Każde wywołanie narzędzia wykonane przez agenta musi być zapisywane w niemodyfikowalnym logu audytowym. Wpis w logu musi zawierać: identyfikator agenta i identyfikator sesji, nazwę narzędzia i wszystkie argumenty, zwracaną wartość, znacznik czasu oraz podane przez agenta uzasadnienie wywołania. Niemodyfikowalność oznacza, że agent ani atakujący nie może usuwać ani zmieniać wpisów w logu. Należy używać magazynu tylko do dopisywania danych (usług logowania w chmurze, baz danych jednokrotnego zapisu lub magazynu WORM).
import hashlib
import json
import time
class ImmutableAuditLog:
def __init__(self, log_backend):
self.backend = log_backend # e.g., CloudWatch, BigQuery, or append-only file
self.previous_hash = '0' * 64 # genesis hash
def record(self, agent_id: str, tool_name: str, args: dict, result, reasoning: str):
entry = {
'agent_id': agent_id,
'tool': tool_name,
'args': args,
'result_summary': str(result)[:500], # truncate large results
'reasoning': reasoning[:1000],
'timestamp': time.time(),
'previous_hash': self.previous_hash # chain entries like a blockchain
}
entry_json = json.dumps(entry, sort_keys=True)
entry['hash'] = hashlib.sha256(entry_json.encode()).hexdigest()
self.backend.append(entry) # append-only, never update
self.previous_hash = entry['hash']
return entry['hash']Wykrywanie nietypowego zachowania agenta
Nawet przy bramkach uprawnień i logach audytowych należy obserwować wzorce nietypowego zachowania, które mogą wskazywać na przejęcie agenta lub jego nieoczekiwane działanie. Sygnały anomalii obejmują: agenta obsługi klienta, który nagle wywołuje narzędzia, z których wcześniej nie korzystał; nietypowy skok częstotliwości wywołań narzędzi przez jednego agenta; argumenty podejrzanie odbiegające od normy (niezwykle długie ciągi znaków, dziwne sekwencje znaków) lub wywołania następujące o nietypowych porach.
from collections import Counter
class AgentBehaviorMonitor:
def __init__(self):
self.tool_call_counts = Counter() # tracks historical tool usage
self.arg_length_history = {} # tracks typical argument lengths
def record_and_check(self, agent_id: str, tool_name: str, args: dict) -> list[str]:
key = f'{agent_id}:{tool_name}'
anomalies = []
self.tool_call_counts[key] += 1
# Flag tools never called before by this agent
if self.tool_call_counts[key] == 1 and tool_name not in COMMON_TOOLS:
anomalies.append(f'First time agent {agent_id} called unusual tool: {tool_name}')
# Flag unusually long arguments (potential injection payload)
total_arg_length = sum(len(str(v)) for v in args.values())
if tool_name not in self.arg_length_history:
self.arg_length_history[tool_name] = []
self.arg_length_history[tool_name].append(total_arg_length)
if len(self.arg_length_history[tool_name]) > 10:
avg = sum(self.arg_length_history[tool_name]) / len(self.arg_length_history[tool_name])
if total_arg_length > avg * 5:
anomalies.append(f'Unusually long arguments for {tool_name}: {total_arg_length} chars (avg: {avg:.0f})')
return anomaliesWygasanie tokenów i zakres sesji
Sesje agentów powinny mieć określony czas życia. Po rozpoczęciu sesji należy wydawać agentowi krótkotrwałe tokeny lub dane uwierzytelniające, a po jej zakończeniu je unieważniać. Jeśli sesja agenta zostanie przejęta w trakcie wykonywania, możliwość wykorzystania jej przez atakującego jest ograniczona czasem wygaśnięcia tokenu. Ograniczenie zakresu sesji gwarantuje również, że pojedynczy przejęty agent nie może zostać użyty do kolejnych ataków kilka dni później.
import secrets
import time
class SessionTokenManager:
def __init__(self, ttl_seconds=3600):
self.tokens = {} # token -> (agent_id, user_id, expires_at)
self.ttl = ttl_seconds
def issue_token(self, agent_id: str, user_id: str) -> str:
token = secrets.token_urlsafe(32)
expires_at = time.time() + self.ttl
self.tokens[token] = (agent_id, user_id, expires_at)
return token
def validate_token(self, token: str) -> dict | None:
if token not in self.tokens:
return None
agent_id, user_id, expires_at = self.tokens[token]
if time.time() > expires_at:
del self.tokens[token] # clean up expired token
return None
return {'agent_id': agent_id, 'user_id': user_id}
def revoke_token(self, token: str):
self.tokens.pop(token, None)
token_manager = SessionTokenManager(ttl_seconds=1800) # 30-minute sessionsTestowanie bezpieczeństwa narzędzi
Bezpieczeństwo warstwy narzędzi należy testować poprzez symulowanie ataków: próbę wywołania ograniczonego narzędzia przez nieuprawnionego agenta, przekazywanie argumentów umożliwiających path traversal, wstrzykiwanie ciągów instrukcji do parametrów narzędzi oraz próby wywołania narzędzi za pomocą wygasłych tokenów. Kompleksowy zestaw testów bezpieczeństwa narzędzi powinien obejmować wszystkie granice uprawnień, wszystkie reguły walidacji oraz wszystkie wyzwalacze wykrywania anomalii.
Projektowanie z myślą o odwracalności
Jeśli to możliwe, narzędzia należy projektować jako odwracalne lub etapowe. Zamiast natychmiast usuwać rekord, można oznaczyć go jako usunięty za pomocą tombstone, aby umożliwić jego przywrócenie. Zamiast od razu wysyłać wiadomość e-mail, można umieścić ją w kolejce „pending send”, która wykona wysyłkę po 5-minutowym oknie na weryfikację. Transakcje finansowe należy etapować, wstrzymując je przed rozliczeniem. Odwracalność nie eliminuje ryzyka bezpieczeństwa, ale znacząco ogranicza skutki udanych ataków.
Szybki test
Sprawdź swoją wiedzę na temat zabezpieczania dostępu agentów do narzędzi z tego rozdziału.
Podsumowanie rozdziału
W tym rozdziale nauczyli się Państwo, że: zasada najmniejszych uprawnień ogranicza uprawnienia narzędzi do zakresu rzeczywiście potrzebnego danej roli agenta; bramki uprawnień na poziomie kodu egzekwują te uprawnienia w sposób, którego nie można ominąć za pomocą prompt injection; a potwierdzenia człowieka w przypadku działań wysokiego ryzyka zapewniają dodatkową warstwę bezpieczeństwa przed wykonaniem nieodwracalnych operacji. Następnie przeprowadzimy ustrukturyzowane ćwiczenie red-teamowe dla aplikacji LLM.
Ucz się Python dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 30
- Lekcje
- 120
Często zadawane pytania
Czy lekcja „Zabezpieczanie dostępu agentów do narzędzi” jest bezpłatna?
Tak — pełny tekst „Zabezpieczanie dostępu agentów do narzędzi” 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 „Zabezpieczanie dostępu agentów do narzędzi”?
Zastosuj zasadę najmniejszych uprawnień do uprawnień narzędzi agentów, wprowadź etapy potwierdzenia przed destrukcyjnymi działaniami i audytuj dzienniki działań agentów w celu wykrywania anomalii. Ć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 3 z 4.
Ile czasu zajmuje lekcja „Zabezpieczanie dostępu agentów do narzędzi”?
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
- Taksonomia ataków typu prompt injection
- Ochrona systemów RAG przed injection
- Zabezpieczanie dostępu agentów do narzędzi
- Testy red team aplikacji LLM