Agent安全工程实现

· 2026-09-09 22:00 · 6 阅读

原创 pandazhengzheng 2026-09-09 22:00 广东

一、沙箱架构设计

Agent调用外部工具时,工具执行必须在沙箱内进行,防止提示注入导致的危险操作。

1.1 工具执行沙箱

import subprocess
import resource
from dataclasses import dataclass
@dataclass
classSandboxConfig:
    timeout_seconds: int = 30
    max_memory_mb: int = 512
    max_cpu_percent: int = 50
    max_file_size_mb: int = 10
    allowed_paths: list = None
    network_allowed: bool = False
classToolSandbox:
def__init__(self, config: SandboxConfig):
        self.config = config
defexecute(self, tool, args):
# 1. 参数校验
ifnot self._validate_args(tool, args):
return {"error""invalid_args"}
# 2. 路径白名单检查
ifnot self._check_paths(args):
return {"error""path_not_allowed"}
# 3. 在隔离环境中执行
try:
            result = self._run_isolated(tool.command, args)
return result
except subprocess.TimeoutExpired:
return {"error""timeout"}
except Exception as e:
return {"error": str(e)}
def_run_isolated(self, command, args):
# 用容器/进程隔离执行
        proc = subprocess.run(
            [command] + args,
            timeout=self.config.timeout_seconds,
            capture_output=True,
            env=self._sandbox_env(),
# 在Linux下可加unshare做命名空间隔离
        )
return {"stdout": proc.stdout, "stderr": proc.stderr, "code": proc.returncode}
def_sandbox_env(self):
        env = {"PATH""/usr/bin:/bin"}
ifnot self.config.network_allowed:
            env["NO_NETWORK"] = "1"
return env

1.2 资源隔离与审计日志

classAuditedSandbox(ToolSandbox):
def__init__(self, config, audit_logger):
        super().__init__(config)
        self.audit = audit_logger
defexecute(self, tool, args, context):
        self.audit.log(
            action="tool_call_start",
            tool=tool.name,
            args=self._redact(args),
            agent_id=context.agent_id,
            timestamp=time.now(),
        )
        result = super().execute(tool, args)
        self.audit.log(
            action="tool_call_end",
            tool=tool.name,
            result_status=result.get("error""success"),
            duration_ms=result.get("duration"),
        )
return result
def_redact(self, args):
"""脱敏参数中的敏感字段"""
        redacted = {}
for k, v in args.items():
if k in self.sensitive_fields:
                redacted[k] = "[REDACTED]"
else:
                redacted[k] = v
return redacted

1.3 权限模型

from enum import Enum
classPermission(Enum):
    READ_FILE = "read_file"
    WRITE_FILE = "write_file"
    EXECUTE = "execute"
    NETWORK = "network"
    DELETE = "delete"
classPermissionModel:
def__init__(self, agent_role, permissions):
        self.role = agent_role
        self.permissions = permissions  # 该角色允许的权限集
defcheck(self, action, resource=None):
if action notin self.permissions:
returnFalse
# 资源级权限检查
if resource andnot self._resource_allowed(action, resource):
returnFalse
returnTrue
def_resource_allowed(self, action, resource):
# 文件路径白名单
if action == Permission.READ_FILE:
return any(
                resource.startswith(prefix)
for prefix in self.allowed_read_paths
            )
if action == Permission.WRITE_FILE:
return any(
                resource.startswith(prefix)
for prefix in self.allowed_write_paths
            )
returnFalse

1.4 动态权限调整

classDynamicPermissionManager:
def__init__(self, base_permissions, risk_monitor):
        self.base = base_permissions
        self.risk = risk_monitor
        self.current = base_permissions.copy()
defadjust(self, context):
        risk_score = self.risk.assess(context)
if risk_score > 0.8:
# 高风险时收紧权限
            self.current = self._restrict(self.base)
elif risk_score < 0.3:
            self.current = self.base
return self.current
def_restrict(self, permissions):
# 移除高风险权限
return permissions - {Permission.WRITE_FILE, Permission.DELETE, Permission.EXECUTE}

1.5 权限组合检测

某些权限单独安全但组合危险(如读文件+网络=数据外泄):

classPermissionCombinationChecker:
def__init__(self):
        self.dangerous_combos = [
            {Permission.READ_FILE, Permission.NETWORK},  # 数据外泄
            {Permission.WRITE_FILE, Permission.EXECUTE},  # 持久化
        ]
defcheck(self, requested_permissions):
for combo in self.dangerous_combos:
if combo.issubset(requested_permissions):
returnFalsef"dangerous_combination: {combo}"
returnTrue"ok"

二、HITL工程实现

2.1 风险分级引擎

classRiskAssessor:
def__init__(self, weights):
        self.weights = weights
defassess(self, action, context):
        score = 0
# 影响面
        score += self.weights["impact"] * self._impact(action, context)
# 可逆性
        score += self.weights["irreversibility"] * (1 - action.reversibility)
# 资产价值
        score += self.weights["asset_value"] * context.asset_value
# 偏离常规
        score += self.weights["novelty"] * self._novelty(action, context)
return score
def_impact(self, action, context):
if action.type == "delete":
return1.0
if action.type == "isolate_host":
return0.8
if action.type == "block_ip":
return0.3
return0.1

2.2 确认界面与异步确认流程

classHITLConfirmFlow:
def__init__(self, threshold=0.7, timeout="4h"):
        self.threshold = threshold
        self.timeout = timeout
asyncdefgate(self, action, context):
        risk = self.risk_assessor.assess(action, context)
if risk < self.threshold:
return {"approved"True"auto"True}
# 创建确认工单
        ticket = self._create_ticket(action, context, risk)
        self._notify_analyst(ticket)
try:
            decision = await self._await_decision(ticket, self.timeout)
            self._audit(decision)
return decision
except TimeoutError:
# 超时降级:不执行,升级
            self._escalate(ticket)
return {"approved"False"reason""timeout"}

2.3 批量确认与审计

classBatchHITL:
"""对同类低风险动作批量确认,避免确认疲劳"""
def__init__(self, max_batch=10, similarity_threshold=0.9):
        self.max_batch = max_batch
        self.similarity = similarity_threshold
        self.pending = []
defsubmit(self, action, context):
        self.pending.append((action, context))
if self._can_batch():
return self._request_batch_confirmation()
return self._request_single_confirmation(action, context)
def_can_batch(self):
if len(self.pending) < 2:
returnFalse
# 检查待确认动作是否足够相似
for i in range(len(self.pending) - 1):
if self._similarity(self.pending[i], self.pending[-1]) < self.similarity:
returnFalse
return len(self.pending) >= self.max_batch orTrue

三、双LLM模式实现

双LLM模式(来自Anthropic的方案):外层不可信LLM做规划,内层特权LLM做执行,两者通信受严格协议约束。

3.1 特权分离架构

用户输入 ─► [外层LLM(不可信)] ─► 动作提案 ─► [协议校验] ─► [内层LLM(特权)] ─► 执行
                ▲                                                      │
                └───────────── 执行结果(受限) ◄─────────────────────┘
classDualLLMArchitecture:
def__init__(self, outer_llm, inner_llm, protocol, sandbox):
        self.outer = outer_llm      # 不可信,做规划
        self.inner = inner_llm      # 特权,做执行
        self.protocol = protocol    # 通信协议
        self.sandbox = sandbox
defrun(self, user_input, context):
for step in range(self.max_steps):
# 1. 外层LLM生成动作提案
            proposal = self.outer.propose(user_input, context)
# 2. 协议校验:提案是否符合允许的动作格式
ifnot self.protocol.validate(proposal):
                context.add_warning("invalid_proposal")
continue
# 3. 内层LLM执行(在沙箱内)
            result = self.sandbox.execute(self.inner, proposal, context)
# 4. 受限结果回传外层(不含敏感细节)
            filtered = self.protocol.filter_result(result)
            context.update(filtered)
if self._is_complete(filtered):
break
return context

3.2 通信协议

classDualLLMProtocol:
def__init__(self, allowed_actions, sensitive_fields):
        self.allowed = allowed_actions
        self.sensitive = sensitive_fields
defvalidate(self, proposal):
if proposal.action notin self.allowed:
returnFalse
ifnot self._check_args_schema(proposal):
returnFalse
returnTrue
deffilter_result(self, result):
"""内层→外层的返回结果过滤"""
        filtered = {}
for k, v in result.items():
if k in self.sensitive:
                filtered[k] = "[FILTERED]"
else:
                filtered[k] = v
return filtered

3.3 降级策略

当内层LLM不可用时:

classDualLLMWithFallback(DualLLMArchitecture):
defrun(self, user_input, context):
try:
return super().run(user_input, context)
except InnerLLMUnavailable:
# 降级为单LLM模式 + 严格HITL
return self._fallback_single_llm(user_input, context)
def_fallback_single_llm(self, user_input, context):
# 每个动作都需HITL确认
for step in range(self.max_steps):
            proposal = self.outer.propose(user_input, context)
ifnot self.hitl.gate(proposal, context).approved:
continue
            result = self.sandbox.execute_direct(proposal)
            context.update(result)
return context

四、提示注入防御工程

4.1 输入净化

classPromptInjectionGuard:
def__init__(self, patterns, llm_judge):
        self.patterns = patterns  # 已知注入模式
        self.llm = llm_judge
defcheck(self, user_input, system_prompt):
# 1. 模式匹配
for pattern in self.patterns:
if pattern.match(user_input):
return {"blocked"True"reason""pattern_match"}
# 2. LLM语义判定:输入是否试图覆盖系统指令
        verdict = self.llm.check_override_attempt(user_input, system_prompt)
if verdict.is_injection:
return {"blocked"True"reason""semantic_injection"}
return {"blocked"False}

4.2 输出过滤

classOutputFilter:
def__init__(self, policy):
        self.policy = policy
deffilter(self, output, context):
# 1. 检查是否包含未授权的工具调用
        tool_calls = self._extract_tool_calls(output)
for call in tool_calls:
ifnot self.policy.allow(call):
return self._redact_call(output, call)
# 2. 检查是否泄露系统提示
if self._contains_system_prompt(output, context):
return self._redact_system(output)
return output

五、实战案例

5.1 企业Agent系统的安全架构

某企业部署内部运维Agent,可执行查询、配置修改、服务重启等操作。

架构

  • 双LLM模式:外层GPT-4做规划,内层专用小模型做执行。

  • 三级权限:只读(自动)、配置修改(HITL确认)、破坏性操作(双人确认)。

  • 全量审计:每个动作记录Agent推理链、工具调用、HITL决策。

经验教训

  • 早期外层LLM可直接调用工具,发生过"Agent误将生产配置当作测试配置修改"。改为双LLM后,内层LLM对"生产"关键词强制触发HITL。

  • HITL确认曾因通知渠道单一(仅邮件)导致响应慢,后增加IM推送,平均确认时间从2小时降至15分钟。

  • 权限组合检测发现过"Agent先读敏感文件再发起网络请求"的可疑序列,及时阻断潜在数据外泄。

5.2 MCP安全网关实现

某企业使用MCP(Model Context Protocol)连接多个工具服务器,需统一安全网关。

classMCPSecurityGateway:

跳转微信打开