安全防护设计:全方位保护你的数据

安全与部署

作为一款自托管应用,MarkStackAI 将安全性作为核心设计原则之一。你的书签、笔记和个人数据存储在自己的服务器上,这本身就是一种隐私保护。但仅靠自托管还不够,应用本身也必须从多个层面构建防御体系。本文详细介绍 MarkStackAI 经过全面安全审计后的安全架构设计。

密码安全:bcrypt 哈希与 DoS 防护

用户密码在存储前经过 bcrypt 算法哈希处理。bcrypt 是目前业界公认的密码哈希标准之一,它内置了自适应的计算成本因子(cost factor),随着硬件性能提升可以调高强度,确保暴力破解始终不可行。

然而 bcrypt 本身存在一个鲜为人知的风险:由于其计算开销较高,攻击者可以发送超长密码(如 1MB)来消耗服务器 CPU 资源,造成拒绝服务。MarkStackAI 在登录和注册的 Schema 层即限制密码最大长度为 128 字符,从输入验证层面阻断这一攻击向量。

时序攻击防护

当用户名不存在时,如果服务器直接返回"用户不存在",攻击者可以根据响应时间的差异来枚举有效用户名。MarkStackAI 在用户名不存在的情况下,仍然执行一次 dummy bcrypt 运算,使得登录成功与失败的响应时间基本一致,从而抵御时序攻击。同时,错误信息统一返回"用户名或密码错误",不区分具体原因。

JWT 认证机制

MarkStackAI 使用 JSON Web Token(JWT)进行用户认证,采用 PyJWT 库(迁移自已停止维护的 python-jose)。Token 的关键设计决策包括:

# 所有 401 错误统一返回同一消息,防止信息泄露
raise HTTPException(
    status_code=401,
    detail="认证失败"
)

RBAC 角色权限控制

系统定义了 admin 和 member 两种核心角色。API 层面的权限控制通过 FastAPI 的依赖注入实现:每个需要认证的端点都声明 current_user 依赖,管理端点额外校验角色。注册接口使用独立的 PublicSignupSchema(不包含 role 字段),从根本上防止角色注入攻击。

SSRF 防护:服务端请求伪造

MarkStackAI 的链接健康检测功能需要从后端发起 HTTP 请求检查书签 URL 是否可达。这一功能天然存在 SSRF 风险——攻击者可能提交内网地址(如 http://192.168.1.1)来探测内部网络。

防护策略采用多层校验:

XSS 防护:跨站脚本攻击

MarkStackAI 的笔记系统支持 Markdown 渲染,这意味着用户内容可能包含 HTML 标签。所有通过 v-html 渲染的内容,无论是笔记预览、文章详情还是代码高亮,都在渲染前经过 DOMPurify 消毒处理。DOMPurify 是业界标准的 HTML 消毒库,能有效移除所有潜在的恶意脚本标签和事件处理器。

此外,后端通过 HTTP 响应头设置了 Content Security Policy(CSP)

Content-Security-Policy: default-src 'self'
Strict-Transport-Security: max-age=31536000

CSP 限制页面只能加载同源资源,即使 XSS 成功注入了脚本标签,浏览器也会拒绝执行外部恶意脚本。

SQL 注入防护

MarkStackAI 使用 SQLAlchemy ORM 操作数据库,所有查询均通过参数化方式构建,天然免疫 SQL 注入。对于搜索功能中使用的 LIKE 查询,系统对用户输入中的 %_\ 通配符进行转义后再拼接 LIKE 模式,防止攻击者通过通配符绕过查询逻辑。

速率限制

通过 slowapi 中间件对关键端点实施速率限制:

在 Nginx 层面还设置了额外的速率限制:auth 端点 5 请求/分钟,通用 API 30 请求/秒,形成双层防护。

文件上传校验

书签导入功能允许上传 HTML 文件。系统对上传文件实施 5MB 大小限制,并校验文件内容是否为合法的 HTML 格式。错误信息经过脱敏处理,不会向客户端暴露服务器文件路径或内部堆栈信息。备份恢复功能额外实施了 Zip Slip 路径校验,通过 resolve() 验证解压路径不会逃逸到目标目录之外。

安全头与统一错误处理

除了前面提到的 CSP 和 HSTS 之外,生产环境还关闭了 Swagger/ReDoc/OpenAPI 文档端点,避免暴露 API 结构。Nginx 配置了 server_tokens off 隐藏版本信息。

所有认证相关的错误消息统一返回"认证失败",不再区分"令牌未提供"、"令牌已过期"、"用户不存在"等具体原因,从根本上防止用户枚举。注册时,无论用户名是否已存在,都返回相同的错误提示文案。

安全不是一次性工程,而是持续的过程。MarkStackAI 已通过全面安全审计,但安全防护需要持续更新。自托管的优势在于,你可以根据自己的安全需求随时调整防护策略,而不是被动等待云服务商的安全修复。
← 返回博客列表