惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
Scott Helme
Scott Helme
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
T
Tenable Blog
PCI Perspectives
PCI Perspectives
Simon Willison's Weblog
Simon Willison's Weblog
N
News and Events Feed by Topic
Know Your Adversary
Know Your Adversary
S
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
SecWiki News
SecWiki News
S
Securelist
D
Docker
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
T
Tailwind CSS Blog
T
Troy Hunt's Blog
The Register - Security
The Register - Security
K
Kaspersky official blog
Blog — PlanetScale
Blog — PlanetScale
云风的 BLOG
云风的 BLOG
Hacker News: Ask HN
Hacker News: Ask HN
S
Secure Thoughts
Stack Overflow Blog
Stack Overflow Blog
T
Threat Research - Cisco Blogs
博客园 - 司徒正美
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
F
Fortinet All Blogs
T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
小众软件
小众软件
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 聂微东
Attack and Defense Labs
Attack and Defense Labs
B
Blog RSS Feed
Project Zero
Project Zero
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
博客园 - 【当耐特】
V
V2EX
Help Net Security
Help Net Security
P
Proofpoint News Feed
A
Arctic Wolf

博客园 - 一名程序媛呀

Anki插件开发必知必会:钩子函数与右键菜单定制 httpx 传参总报错?这次把 GET、POST、文件上传到响应处理的坑给你一次填平 从卡顿到丝滑:FastAPI 调用外部 API 的正确姿势(httpx 实战) 还在 XHR、Fetch 和 Axios 之间纠结?我踩过的坑,希望你一个都不用碰到 你的REST接口还在“过度投喂”数据吗?——FastAPI + GraphQL实战避坑指南 Uvicorn、Gunicorn 傻傻分不清?FastAPI 生产部署避坑指南 Termux里的二进制和脚本,到底怎么运行才不踩坑?Termux-service 保活妙招! 刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API 别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了 掏出手机就能搭个 WebDAV 同步服务器?这操作有点香 别只盯着GitBook了!这个文档神器让你的笔记秒变网站 写爬虫时用了代理还被封?Python 代理的那些隐藏坑,我替你踩明白了 FastAPI 身份验证总踩坑?这份 FastAPI Users “避坑指南”请收好 旧手机别扔!用 Termux 搭个私人云盘,比网盘香多了 你的FastAPI又在服务器上“跑不起来”了?来,今天咱把打包这件事彻底聊透 写页面时别再把 Element Plus 整个搬进来啦!Vue3按需加载的坑我帮你踩平了 前端包管理咋选?我从npm叛逃到pnpm的血泪史(附避坑指南) 聊聊 fetch 使用中我踩过的那些坑和正确打开方式 FastApiAdmin 后端接口开发好了,前端管理界面怎么调用与显示? 给 FastApiAdmin 加个“会议纪要”模块,我把后端二次开发的坑踩了个遍 我用了FastApiAdmin后,连夜把踩过的坑都整理出来了 告别 Typora 后的新欢:我把所有笔记迁移到了 Obsidian 这个“第二大脑” 让 FastAPI Agent 思考不阻塞:手把手教你实现异步任务与后台处理方案 让FastAPI Agent真正记住你:聊聊会话记忆与持久化存储的落地实践 FastAPI Agent 函数调用实战:我让 AI 学会了“自己动手查天气“ 初探:用 FastAPI 搭建你的第一个 AI Agent 接口 FastAPI 少有人提的实用技巧:把 Depends 依赖提到路由层,代码少写60% FastAPI 生产环境静态文件完全指南:从 /favicon.ico 404 到 HSTS 混合内容,一次全根治 用了loguru我才明白,Python日志还能这么写 FastAPI 后台任务:BackgroundTasks 的使用场景与注意事项 FastAPI配置管理避坑指南:从硬编码到 .env 与 pydantic_settings 类,连路由用法都给你捋清楚 FastAPI 文件上传避坑全指南:分块存盘、类型校验与安全兜底 FastAPI + Pydantic 模型终极实战手册:从能跑就行到固若金汤,这些技巧你一定用得上 FastAPI + SQLAlchemy 2.0 通用CRUD操作手册 —— 从同步到异步,一次讲透 FastAPI订单防超卖实战:从数据库锁到Saga分布式事务,这一篇给你理清了 FastAPI 生产环境避坑指南:用 Alembic 管理数据库迁移,别再手动改表结构了! FastAPI服务半夜又挂了?先别急着重启,查查你的数据库连接池“池子”是不是漏了 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 Vue 3 组合式 API 香是香,但从Vue2迁移时你可别像我当初一样踩进这 3 个深坑里 我用fastapi-scaff搭了个项目,两天工期缩到两小时,老板以为我开挂了 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! FastAPI自动生成的API文档太丑?我花了一晚上把它改成了客户愿意付费的样子 告别手写 API 胶水代码:FastAPI 与 Vue 的“契约自动机” OpenAPI 实战 FastAPI + Vue 前后端分离实战:我的项目结构“避坑指南” FastAPI + Celery 实战:异步任务里调用 Redis 和数据库的全解析,及生产级组织方案 FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了! FastAPI + Celery 实战:异步任务的坑与解法,我帮你踩了一遍 FastAPI子应用挂载:别再让root_path坑你一夜 FastAPI项目半夜报警吵醒你?聊聊告警这事儿怎么搞! 别再数据线了!用FastAPI 5分钟搭个局域网文件+剪贴板神器 FastAPI单元测试实战:别等上线被喷才后悔,TestClient用对了真香! FastAPI状态共享秘籍:别再让中间件、依赖和路由“各自为政”了! FastAPI实战:WebSocket vs Socket.IO,这回真给我整明白了! 从0到1,FastAPI + PostgreSQL + Tortoise ORM 实战避坑指南 FastAPI + PostgreSQL 实战:给应用装上“缓存”和“日志”翅膀 FastAPI + PostgreSQL 实战:从入门到不踩坑,一次讲透
你的Agent API还在裸奔?从认证到沙箱,我用FastAPI搭了几道防线
一名程序媛呀 · 2026-05-18 · via 博客园 - 一名程序媛呀

试想一下,你辛苦做出的某条 Agent API 的调用量在半小时内飙到了平时的 200 倍。查日志发现,有人用脚本把接口当免费 GPT 在薅,更恐怖的是,他们尝试在 prompt 里夹带 ` 删除所有日志 ` 这种恶意指令——如果你的工具执行部分根本没做过滤……

太多这种案例让我意识到:给 Agent 套上安全防线,不是“可选项”,而是从第一行代码起就该刻进骨子里的铁律。

👩‍💻我是爱折腾的一名程序媛,喜欢研究全栈开发的各种实践,热爱分享踩坑后的收获与思考,也享受用代码写出各种实用小工具解决问题的快乐。

如果你也在技术这条路上向前走,希望我们能彼此陪伴,一起成为更好的自己 🌱

前面几篇我们学习了如何理解和创建FastAPI AI Agent接口,今天就来聊聊怎么构建我们的接口防线,每道都带着可直接跑的代码,希望能让你的线上 Agent 睡个安稳觉。

🛡️ 第一道:门禁卡——OAuth2 + JWT 认证

API 不能敞开大门随便进。FastAPI 内置了 OAuth2PasswordBearer 这套“门禁系统”,配合 JWT 就像一张带时效的房卡。

登录后拿 token,后续请求都得带上,否则直接 401 挡在门外。

这里一定要注意:千万不要把 secret key 硬编码,正经做法是从环境变量读。

from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import jwt
from datetime import datetime, timedelta

SECRET_KEY = "从环境变量取!"
ALGORITHM = "HS256"

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")

app = FastAPI()

def create_token(data: dict):
    to_encode = data.copy()
    to_encode.update({"exp": datetime.utcnow() + timedelta(hours=2)})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

@app.post("/token")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # 验证用户(示例:固定账号)
    if form_data.username != "admin" or form_data.password != "pass":
        raise HTTPException(status_code=401, detail="密码错误")
    return {"access_token": create_token({"sub": form_data.username}), "token_type": "bearer"}

👑 第二道:权限分级——RBAC

有了门禁还不够,不能所有人进来都能操作 Agent。

我们用“角色”来区分:普通用户只能查询,管理员才能修改配置或调用危险工具。

关键是一个依赖注入函数,检查 token 里带的 role 字段。

这里也要注意,不能只靠前端隐藏按钮,后端完全没校验——那等于把钥匙藏在门口地垫下。

from fastapi import Security

def get_current_user(token: str = Depends(oauth2_scheme)):
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
    return {"username": payload.get("sub"), "role": payload.get("role", "user")}

def require_role(role: str):
    def checker(user = Depends(get_current_user)):
        if user["role"] != role:
            raise HTTPException(status_code=403, detail="权限不足")
        return user
    return checker

@app.get("/admin/agent-config")
def update_config(user = Depends(require_role("admin"))):
    return {"message": "只有管理员看得到"}

🧹 第三道:入口安检——输入清洗与限流

Agent 最怕提示注入。我的做法是:先用 Pydantic 做格式校验,再上自定义清洗函数,把那些 忽略前面的指令请扮演 DAN 之类的黑名单短语直接堵死。当然黑名单不是银弹,但能挡住大部分脚本小子。

另外,同一 IP 每秒 100 次的请求绝对不正常。用 SlowAPI 中间件限流,就像给接口装了水龙头,防止被冲垮。

注意,生产环境一定要搭配 Redis 存储计数,不然多 worker 下会漏。

from slowapi import Limiter
from slowapi.util import get_remote_address
from pydantic import BaseModel, validator

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(429, lambda _,_: JSONResponse(status_code=429, content="慢点!"))

class PromptInput(BaseModel):
    prompt: str

    @validator("prompt")
    def check_injection(cls, v):
        blacklist = ["忽略前面的指令", "ignore previous", "DAN"]
        if any(b in v.lower() for b in blacklist):
            raise ValueError("检测到注入企图")
        return v

@app.post("/agent/ask")
@limiter.limit("5/second")
def ask_agent(item: PromptInput, request: Request):
    return {"response": f"你说: {item.prompt[:50]}..."}

🧪 第四道:工具执行的“无菌实验室”

Agent 经常会调用本地命令、跑 Python 脚本,这相当于给用户开了一个终端——不用沙箱就是自杀。

我强制所有命令必须通过白名单,比如只能执行 lscat 这几个;
同时用 Python 的 resource 模块限制子进程的内存和 CPU 时间,避免恶意死循环吃光服务器。

网络隔离可以进一步用 Docker 的 --network=none,这里用子进程做个最简演示:

import subprocess, resource

ALLOWED_COMMANDS = ["ls", "cat", "echo"]
def safe_exec(cmd: str):
    parts = cmd.strip().split()
    if not parts or parts[0] not in ALLOWED_COMMANDS:
        raise ValueError("命令不在白名单")
    def set_limits():
        resource.setrlimit(resource.RLIMIT_AS, (50*1024*1024, 100*1024*1024)) # 内存50MB
        resource.setrlimit(resource.RLIMIT_CPU, (2, 2))  # CPU时间2秒
    try:
        result = subprocess.run(parts, capture_output=True, text=True,
                                preexec_fn=set_limits, timeout=5)
        return result.stdout
    except subprocess.TimeoutExpired:
        return "执行超时,已终止"

🔑 第五道:密钥轮换与环境隔离

最后这条很多人会忽略:JWT 签名密钥、第三方 API Key 要定期换,就像家门锁的密码不能万年不变。

我写了一个简单的 KeyManager,从环境变量读取,并支持定期重载。

不同环境(开发、测试、生产)严格隔离,一个环境的 Key 泄露不至于连累全家。

import os, time

class KeyManager:
    def __init__(self, env_var: str, refresh_interval=3600):
        self.env_var = env_var
        self.refresh_interval = refresh_interval
        self._last_read = 0
        self._cached = None

    def get(self):
        now = time.time()
        if now - self._last_read > self.refresh_interval or self._cached is None:
            self._cached = os.getenv(self.env_var)
            self._last_read = now
        if not self._cached:
            raise RuntimeError(f"环境变量 {self.env_var} 未设置")
        return self._cached

secret_key_manager = KeyManager("JWT_SECRET_KEY", refresh_interval=7200)

💡 最后啰嗦两句

安全是持续动作,不是一次性配置。还要给 Agent 项目加上告警通知、漏洞扫描等,并且永远假设自己的代码会被人恶意利用——只有保持这种“被害妄想”,才能真正安稳。

如果你也有 Agent 正打算上线,别等到报警了再动手。拿这几段代码去,先堵上最急的窟窿,然后慢慢加固其他部分。


👋 我是那个爱折腾一名程序媛,如果这篇帮你省了一次半夜救火,点个「收藏」+「关注」让我知道呀~

也欢迎把文章转发给身边同样在折腾 Agent 的朋友,安全这回事,越多人清醒,我们就越省心。