图片生成服务一旦暴露在公网,被刷图、盗用API、恶意上传超大文件都是迟早的事。很多人在VPS上部署了Stable Diffusion WebUI或ComfyUI,配好反向代理就直接用,结果几天后发现GPU跑满、磁盘爆掉、账单飙升。本文直接讲四个必须落地的安全防护点:上传限制、队列、鉴权和资源隔离,适合用Docker部署AI工具的站长和开发者参考。

上传限制:先拦住大文件和恶意格式
图片生成服务通常允许用户上传参考图、蒙版或LoRA文件,如果不做限制,攻击者可以上传几百MB的图片甚至脚本文件。
Nginx层限制上传大小
在反向代理配置里加一行:
nginx
client_max_body_size 20m; # 限制上传最大20MB,根据你的模型需求调整
如果用的是Caddy或Traefik,也有对应参数。这一步能挡住大部分扫描器。
应用层校验文件类型
后端不要只依赖前端JS校验,要在Python/Node.js服务里检查MIME类型和文件头。例如Python用`python-magic`库:
python
import magic
mime = magic.from_file(uploaded_file, mime=True)
if mime not in ['image/png', 'image/jpeg', 'image/webp']:
raise ValueError("只允许PNG/JPEG/WEBP格式")
限制单用户上传频率
用Nginx的`limit_req`模块或应用层限流中间件,比如Flask-Limiter。防止脚本批量上传。
队列:防止并发请求压垮GPU
图片生成是计算密集型任务,没有队列管理,同时来10个请求GPU直接OOM,服务崩溃。
使用Redis + Celery或RQ
把生成任务放入队列,Worker逐个消费。以RQ为例:
pip install rq redis
rq worker high default low
在API视图里:
python
from rq import Queue
from redis import Redis
redis_conn = Redis()
q = Queue(connection=redis_conn)
job = q.enqueue(generate_image, user_input, result_ttl=3600)
return {"job_id": job.id}
简单队列方案:使用队列长度限制
如果不想引入Redis,可以在应用内用`asyncio.Queue`(Python)或`bull`(Node.js)实现内存队列,但重启会丢失任务,仅适合开发测试。
设置最大并发数
在Docker Compose里限制容器CPU和内存:
yaml
services:
image-gen:
deploy:
resources:
limits:
cpus: '4'
memory: 8G
同时应用层通过信号量控制并发数,比如Python的`asyncio.Semaphore(2)`。
鉴权:不让陌生人直接调用API
图片生成API一旦暴露,任何人都可以调用你的显卡算力。必须加鉴权。
API Key鉴权
最简单的方案:生成一个随机字符串,客户端在请求头中携带`Authorization: Bearer your-api-key`。后端用中间件验证:
python
from flask import request, abort
API_KEY = "sk-xxxxxxxxxxxx"
@app.before_request
def check_api_key():
if request.endpoint in ['generate']:
key = request.headers.get('Authorization', '').replace('Bearer ', '')
if key != API_KEY:
abort(401)
注意:API Key不要硬编码在代码里,用环境变量`API_KEY`。
JWT鉴权(适合多用户)
用PyJWT生成带过期时间的token,用户登录后获取,后续请求携带。比静态Key更安全。
Nginx层加Basic Auth
如果只是简单保护WebUI页面,可以用htpasswd:
htpasswd -c /etc/nginx/.htpasswd admin
在server块加上:
nginx
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
但Basic Auth不适合API调用,因为每次都要传密码。
资源隔离:防止一个用户搞垮整个服务
同一台VPS上可能跑多个AI服务,或者多个用户共用。资源隔离是最后一道防线。
Docker容器隔离
每个图片生成服务跑在独立容器里,限制CPU、内存、磁盘I/O。用`docker run –memory=4g –cpus=2`。
用户工作目录隔离
如果服务支持多用户(如Stable Diffusion WebUI的`–api`模式),在文件系统上为每个用户创建独立目录,防止A用户读取B用户的生成图片或模型。
使用Linux cgroups或systemd scope
更精细的资源控制可以用cgroups v2,限制某个进程组的CPU和内存上限。
网络隔离
不要让图片生成服务直接暴露公网,通过反向代理(Nginx/Caddy)转发,且只开放必要端口(如443)。内部服务监听127.0.0.1。
老鸟叮嘱
•千万别把API Key明文写在Git仓库里。用`.env`文件,并加入`.gitignore`。
•队列的Redis一定要加密码。默认无密码的Redis暴露在公网等于送分。
•上传限制不要只依赖前端。抓包可以直接绕过JS。
•生产环境不要用root用户跑服务。创建一个专用系统用户,比如`imguser`。
•定期检查日志。`tail -f /var/log/nginx/access.log | grep -E "403|500"` 看看有没有异常请求。
FAQ
Q1:我只有1G内存的VPS,能跑图片生成服务吗?
A:勉强能跑轻量模型(如TinySD),但建议至少4G内存+2G显存(或共享内存)。如果VPS没有独立显卡,CPU推理很慢,队列会积压。
Q2:上传限制设多大合适?
A:看你的模型需要。Stable Diffusion的参考图一般不超过10MB,LoRA文件通常50MB以内。建议设20MB,特殊需求再单独调。
Q3:队列任务超时怎么办?
A:设置任务超时时间,比如RQ的`job.timeout=300`。超时后自动重试或标记失败,避免死任务卡住Worker。
Q4:JWT鉴权比API Key好在哪?
A:JWT可以设置过期时间、携带用户角色,支持刷新令牌。适合多用户场景。API Key适合单用户或内部服务。
Q5:Docker资源限制写多少?
A:根据你的VPS配置。比如2核4G的VPS,给容器分配1.5核和3G内存,留一些给系统和其他服务。
Q6:有没有现成的安全防护工具?
A:可以用Cloudflare WAF(Web应用防火墙)做速率限制和IP黑名单,但注意图片生成API请求体较大,要调整Cloudflare的请求大小限制。
图片生成服务的安全防护不是一次配置就完事的,需要结合日志监控和定期更新。上传限制、队列、鉴权和资源隔离这四步做好,基本能挡住绝大多数恶意攻击。
转载请注明出处:https://www.zhujixuan.com/jishujiaocheng/9928.html 商家投稿邮箱:zhujixuanblog@qq.com
