☰
如何读懂 TranslateBooksWithLLMs 安全设计:路径遍历防护、密钥管理与上传文件安全指南
2026/10/4 5:08:55 网站建设 项目流程

如何读懂 TranslateBooksWithLLMs 安全设计:路径遍历防护、密钥管理与上传文件安全指南

【免费下载链接】TranslateBooksWithLLMsTranslate full-length books and documents with Ollama, OpenAI-compatible, Gemini, Mistral, DeepSeek, Poe or OpenRouter. Preserves formatting. Resumes where you left off. No file size limits.项目地址: https://gitcode.com/gh_mirrors/tr/TranslateBooksWithLLMs

TranslateBooksWithLLMs 是一款使用 Ollama、OpenAI、Gemini、Mistral、DeepSeek、Poe 或 OpenRouter 翻译整本图书与文档的开源工具。本文带你深入它的安全设计:路径遍历防护如何阻挡恶意文件路径、API 密钥如何安全轮换、上传文件经过哪些安检关卡——即使是新手也能看懂这套"多层防御"。

🔍 安全设计总览:三道防线

该项目把安全能力拆成了清晰的三层,每层各司其职:

防线核心模块防御目标
路径层path_validator.py阻止路径遍历、任意文件读取
密钥层api_keys.py、key_pool.py防止密钥泄露、限流失败
文件层security.py危险扩展名、ZIP Slip、Zip 炸弹

🛡️ 路径遍历防护:让恶意路径无路可走

攻击者常试图用../../etc/passwd这样的路径"逃"出目录读取敏感文件。项目通过 PathValidator 类来拦截:

  • 解析后再比较:is_within_directory方法先对路径执行resolve()(跟随符号链接、规范化..),再用Path.relative_to逐段比较——而不是用字符串startswith。注释里明确说明原因:'/uploads-evil'会被startswith误判为在'/uploads'内部。
  • 先查包含关系,再查文件存在:validate_upload_path中,越界路径的错误提示永远不会泄露"这个文件是否存在",避免信息侧信道。
  • 文件名双重校验:validate_filename同时拦截绝对路径(含 Windows 盘符如C:)、../与..\序列、超过 255 字符的超长文件名。

想亲手验证这些行为?项目提供了 tests/unit/test_zip_slip.py 等测试文件,展示了"如果这些校验缺失会发生什么"。

ZIP Slip:档案解包的经典陷阱

EPUB 和 DOCX 本质是 ZIP 包,其中的条目名由攻击者控制。security.py 中的is_safe_archive_member函数会拒绝:

  • 以/开头的 POSIX 绝对路径、UNC 路径;
  • Windows 盘符路径(如C:前缀);
  • 任一路径段等于..的条目;
  • 含控制字符(包括 NUL)的名称。

配套的safe_extract_zip采用"全部校验通过才写入一个字节"的策略,被拒的压缩包不会留下任何残留文件——这就是纵深防御:名称检查之后,还会对解析后的实际落盘位置做第二道relative_to复核。

🔑 密钥管理:前端从不传输真实密钥

这是该项目最精巧的设计之一,见 api_keys.py:

  1. 哨兵值机制:当密钥配置在服务器.env文件中时,前端界面发送的只是一个占位符__USE_ENV__,由服务端在 resolve_api_key 函数中还原为真实环境变量值。浏览器里永远看不到你的真实密钥。
  2. 单一可信来源:注释中提到,这段逻辑曾复制在四个路由文件中,分化导致 issue #200(占位符被原样转发给 Gemini)。现在所有端点共用一个解析函数,杜绝漂移。
  3. 端点隔离:allow_env_fallback参数保证——当用户自行选择了目标服务器地址时,服务器存储的密钥绝不被发往客户端挑选的端点。

多密钥轮换:429 限流自动故障转移

如果你在.env中配置了多个同厂商密钥(逗号分隔),KeyPool 类会用轮询方式轮换它们:

  • 某密钥收到 HTTP 429(限流)时,被标记为节流状态,下一个请求自动切换到其他可用密钥,无需等待;
  • 使用单调时钟(time.monotonic())记录节流截止时间,避免系统时间漂移导致的 bug;
  • 所有变更操作由asyncio.Lock保护,可安全地在并发协程间共享。

完整的配置说明见 docs/API_KEY_ROTATION.md。

📁 上传文件安全:六步安检流程

每个上传文件都要经过 SecureFileHandler 的多重检查,流程设计值得细品:

第 1 步:文件名清洗用os.path.basename剥离一切路径成分,再正则拦截<>:"|?*及控制字符。随后用secrets.token_hex(8)生成随机前缀重命名文件——即使两个同名文件上传也永不冲突。

第 2 步:扩展名黑名单.exe、.bat、.js、.ps1、.iso等可执行与系统文件扩展名一票否决,即使允许"任意扩展名+内容探测"的宽松模式也绝不放行。

第 3 步:内容扫描

  • 文本文件前 8KB 扫描<script、javascript:、<?php、eval(等 16 种可疑模式,命中即拒;
  • EPUB/DOCX 内部条目再跑一遍find_unsafe_archive_member,并拒绝包内.exe/.jar等可疑文件、条目数超过 10000 的Zip 炸弹;
  • PDF 校验%PDF-头、页数上限 5000、拒绝加密文档,并探测扫描版(无文字层)给出友好警告。

第 4 步:临时文件原子落盘文件先写入.tmp临时后缀,内容校验通过后才重命名为正式文件;任何一步失败都通过_cleanup_temp_file清理,不会残留半成品。

第 5 步:大小与生命周期单文件上限 100MB;cleanup_old_files定期清理超过 24 小时的上传文件,防止磁盘被占满。

🚪 访问控制:会话令牌挡住"路过式"攻击

auth.py 解决了本地 Web 服务的经典问题:用户浏览网页时,恶意页面可能借浏览器向本地 API 发起跨域请求(drive-by attack)。

  • 启动即铸造:每次服务启动用secrets.token_urlsafe(32)生成约 256 位熵的随机令牌,随页面 HTML 交付给同源前端,从不持久化——进程重启即失效;
  • 全量门禁:before_request钩子拦截所有/api/路由,令牌通过X-API-Token请求头或查询参数携带;
  • 防时序攻击:令牌比对使用secrets.compare_digest恒定时间比较;
  • 最小豁免:仅页面本身、静态资源和健康检查端点/api/health免令牌,且后者刻意不暴露任何敏感信息;
  • 配合 CORS 收紧:通配Access-Control-Allow-Origin已移除,双管齐下同时封死跨域读取与 CSRF 向量。

相关回归测试见 tests/unit/test_api_auth.py。

✅ 给新手的三点启示

  1. 校验要"解析后比较":任何涉及路径的代码,都应在resolve()之后用结构化方法(relative_to)而非字符串前缀判断包含关系。
  2. 密钥不该过网络:用__USE_ENV__这类哨兵值让浏览器只传占位符,是把"配置"与"传输"解耦的经典手法。
  3. 安全测试要覆盖失败路径:从 tests/unit/test_zip_slip.py、tests/unit/test_api_auth.py 可以看出,该项目为每道防线都保留了独立测试,这正是安全能力不随重构腐化的保障。

更多供应商密钥与端点配置细节,可参考 docs/PROVIDERS.md;部署时的安全注意事项见 deployment/VALIDATION.md。

【免费下载链接】TranslateBooksWithLLMsTranslate full-length books and documents with Ollama, OpenAI-compatible, Gemini, Mistral, DeepSeek, Poe or OpenRouter. Preserves formatting. Resumes where you left off. No file size limits.项目地址: https://gitcode.com/gh_mirrors/tr/TranslateBooksWithLLMs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询