{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/",
  "atlas": "https://www.pystone.net/?node=python-desktop-app-build-publish-protection#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection.md",
  "context": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:python-desktop-app-build-publish-protection",
  "slug": "python-desktop-app-build-publish-protection",
  "title": "Python 桌面应用构建、发布与代码保护",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "Python 桌面应用构建、发布与代码保护",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "7dcd986e601bde43ff0d479d05f1bb97aaadbb8509a254cf51fe4ff6b53223ed",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "Python 桌面应用构建、发布与代码保护",
      "anchor": "python-桌面应用构建发布与代码保护",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#python-%E6%A1%8C%E9%9D%A2%E5%BA%94%E7%94%A8%E6%9E%84%E5%BB%BA%E5%8F%91%E5%B8%83%E4%B8%8E%E4%BB%A3%E7%A0%81%E4%BF%9D%E6%8A%A4"
    },
    {
      "depth": 2,
      "text": "先明确发布目标",
      "anchor": "先明确发布目标",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E5%85%88%E6%98%8E%E7%A1%AE%E5%8F%91%E5%B8%83%E7%9B%AE%E6%A0%87"
    },
    {
      "depth": 2,
      "text": "工具分工",
      "anchor": "工具分工",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E5%B7%A5%E5%85%B7%E5%88%86%E5%B7%A5"
    },
    {
      "depth": 3,
      "text": "PyInstaller：应用打包",
      "anchor": "pyinstaller应用打包",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#pyinstaller%E5%BA%94%E7%94%A8%E6%89%93%E5%8C%85"
    },
    {
      "depth": 3,
      "text": "Nuitka：编译整个应用或模块",
      "anchor": "nuitka编译整个应用或模块",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#nuitka%E7%BC%96%E8%AF%91%E6%95%B4%E4%B8%AA%E5%BA%94%E7%94%A8%E6%88%96%E6%A8%A1%E5%9D%97"
    },
    {
      "depth": 3,
      "text": "Cython：编译选定模块",
      "anchor": "cython编译选定模块",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#cython%E7%BC%96%E8%AF%91%E9%80%89%E5%AE%9A%E6%A8%A1%E5%9D%97"
    },
    {
      "depth": 3,
      "text": "混淆",
      "anchor": "混淆",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E6%B7%B7%E6%B7%86"
    },
    {
      "depth": 2,
      "text": "代码签名不是代码加密",
      "anchor": "代码签名不是代码加密",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E4%BB%A3%E7%A0%81%E7%AD%BE%E5%90%8D%E4%B8%8D%E6%98%AF%E4%BB%A3%E7%A0%81%E5%8A%A0%E5%AF%86"
    },
    {
      "depth": 2,
      "text": "客户端不能安全保存服务端秘密",
      "anchor": "客户端不能安全保存服务端秘密",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%B8%8D%E8%83%BD%E5%AE%89%E5%85%A8%E4%BF%9D%E5%AD%98%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%A7%98%E5%AF%86"
    },
    {
      "depth": 2,
      "text": "可重复发布流程",
      "anchor": "可重复发布流程",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E5%8F%AF%E9%87%8D%E5%A4%8D%E5%8F%91%E5%B8%83%E6%B5%81%E7%A8%8B"
    },
    {
      "depth": 3,
      "text": "1. 锁定环境",
      "anchor": "1-锁定环境",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#1-%E9%94%81%E5%AE%9A%E7%8E%AF%E5%A2%83"
    },
    {
      "depth": 3,
      "text": "2. 测试打包边界",
      "anchor": "2-测试打包边界",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#2-%E6%B5%8B%E8%AF%95%E6%89%93%E5%8C%85%E8%BE%B9%E7%95%8C"
    },
    {
      "depth": 3,
      "text": "3. 生成与核验产物",
      "anchor": "3-生成与核验产物",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#3-%E7%94%9F%E6%88%90%E4%B8%8E%E6%A0%B8%E9%AA%8C%E4%BA%A7%E7%89%A9"
    },
    {
      "depth": 3,
      "text": "4. 发布与回滚",
      "anchor": "4-发布与回滚",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#4-%E5%8F%91%E5%B8%83%E4%B8%8E%E5%9B%9E%E6%BB%9A"
    },
    {
      "depth": 2,
      "text": "选择建议",
      "anchor": "选择建议",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E9%80%89%E6%8B%A9%E5%BB%BA%E8%AE%AE"
    },
    {
      "depth": 2,
      "text": "参考资料",
      "anchor": "参考资料",
      "citation": "https://www.pystone.net/notes/python-desktop-app-build-publish-protection/#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:application-and-cloud-engineering",
      "title": "应用开发与云端工程",
      "url": "https://www.pystone.net/notes/application-and-cloud-engineering/",
      "atlas": "https://www.pystone.net/?node=application-and-cloud-engineering#knowledge-atlas",
      "label": "应用开发与云端工程",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "桌面应用开发中的“Python桌面应用构建发布与代码保护”导航项",
      "citation": "https://www.pystone.net/notes/application-and-cloud-engineering/#%E6%A1%8C%E9%9D%A2%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91"
    }
  ],
  "contentMarkdown": "# Python 桌面应用构建、发布与代码保护\n\n> [!note] 核心结论\n> “打包”“编译扩展”“混淆”“签名”和“秘密管理”解决的是不同问题。客户端代码无法做到绝对保密；更现实的目标是提高逆向成本、保护供应链、缩小秘密暴露面，并建立可重复发布流程。\n\n## 先明确发布目标\n\n开始选工具前确认：\n\n- 支持 Windows、macOS、Linux 中的哪些系统与 CPU 架构；\n- 单文件、目录包、安装器还是商店分发；\n- 是否允许首次启动解压，启动速度和体积预算是多少；\n- 是否包含 Qt、GPU、原生 DLL、数据文件或插件；\n- 是否需要离线运行、自动更新、崩溃报告和企业签名；\n- 哪些代码或算法确实需要提高逆向门槛。\n\n构建产物通常需要在每个目标操作系统上分别构建和测试，不应假设一次打包即可跨平台运行。\n\n## 工具分工\n\n### PyInstaller：应用打包\n\nPyInstaller 分析导入，把 Python 解释器、模块和资源组织为可分发目录或单文件。它主要解决依赖收集和启动，不会把全部业务逻辑变成难以逆向的原生机器码。\n\n```powershell\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npython -m pip install --upgrade pip\npython -m pip install pyinstaller\npyinstaller --clean --noconfirm app.spec\n```\n\n推荐维护 `.spec` 文件，明确入口、数据文件、隐藏导入、运行时钩子和图标。`--onefile` 便于交付，但通常需要启动时解压，排障和增量更新也更困难；发布前应同时评估 `onedir`。\n\n### Nuitka：编译整个应用或模块\n\nNuitka 将 Python 程序转换并通过 C/C++ 工具链构建，可以用于独立应用和扩展模块。它可能提高部分逆向门槛和性能，但效果依赖代码形态、插件配置和目标平台，并不等于自动获得 C++ 性能。\n\n```powershell\npython -m nuitka --standalone --enable-plugin=pyside6 app.py\n```\n\n具体选项与商业插件能力会变化，发布配置应锁定版本并以当前官方手册为准。\n\n### Cython：编译选定模块\n\nCython 适合把性能敏感或希望隐藏实现细节的模块编译成扩展。它需要构建工具链，且动态 Python 行为仍可能限制优化。把稳定算法边界提取为小模块，通常比把整个 UI 应用一次性 Cython 化更容易维护。\n\n```text\nPython UI / orchestration\n        ↓\ntyped Cython module → platform extension (.pyd/.so)\n```\n\n### 混淆\n\n混淆可以改变标识符、控制流或封装方式，以增加阅读成本，但会降低可调试性并可能影响反射、序列化和插件加载。使用商业保护工具前要验证：\n\n- 许可证是否允许目标分发方式；\n- 工具是否仍维护并支持当前 Python；\n- 崩溃符号与堆栈能否在内部还原；\n- 是否引入在线授权服务或新的供应链风险。\n\n厂商声称的“不可逆”“完全保护”不应直接当作安全结论。\n\n## 代码签名不是代码加密\n\n代码签名用于让操作系统和用户验证发布者及文件完整性，不能阻止逆向。典型流程是：\n\n1. 在干净环境产生最终二进制和安装器。\n2. 生成软件物料清单、版本与摘要。\n3. 由隔离的签名任务调用证书或硬件密钥。\n4. 校验签名和时间戳。\n5. 将已签名产物发布到不可变制品库。\n\nWindows 可使用 Authenticode，macOS 使用 Developer ID、公证与 stapling。证书私钥不得进入仓库、普通构建机或日志。\n\n## 客户端不能安全保存服务端秘密\n\n只要应用能离线解密并使用某个固定 API 密钥，拥有应用和调试能力的人原则上也能取得它。不要把数据库口令、云主密钥或可长期调用高权限 API 的 Token 打包进程序。\n\n优先方案：\n\n- 把高权限操作放到服务端；\n- 用户登录后签发短期、限权令牌；\n- 在操作系统凭据库保存用户级刷新凭据；\n- 服务端实施配额、撤销、审计和设备/账号风险控制；\n- 能用公钥验证的场景，不向客户端分发私钥。\n\n## 可重复发布流程\n\n### 1. 锁定环境\n\n- 使用受支持的 Python 版本和独立虚拟环境。\n- 锁定直接与传递依赖，记录哈希和许可证。\n- 固定打包器、编译器、Qt 与系统 SDK 版本。\n\n### 2. 测试打包边界\n\n- 单元测试与集成测试先于打包。\n- 在干净虚拟机执行安装、启动、升级、卸载。\n- 测试非 ASCII 用户名、只读目录、无网络、代理和低权限账号。\n- 校验 Qt 插件、字体、证书、图标和动态库加载。\n\n### 3. 生成与核验产物\n\n- 清理旧构建目录，避免把残留文件误收进包。\n- 输出版本、提交、依赖清单、摘要和构建日志。\n- 执行恶意软件扫描和基本供应链检查。\n- 签名后再次验证，确保后续步骤没有改写文件。\n\n### 4. 发布与回滚\n\n- 分阶段发布，保留上一稳定版。\n- 更新包验证签名与摘要，防止降级和中间人替换。\n- 崩溃报告不收集口令、Token、个人路径或文档内容。\n- 能快速撤销证书、关闭版本和回滚服务端协议。\n\n## 选择建议\n\n| 目标 | 优先评估 |\n| --- | --- |\n| 快速把 Python 应用交付给用户 | PyInstaller `onedir`/`onefile` |\n| 编译整个应用并提高逆向门槛 | Nuitka |\n| 加速或隐藏少量稳定算法模块 | Cython |\n| 提供发布者身份与完整性验证 | 平台代码签名 |\n| 保护 API/数据库秘密 | 服务端代理、短期令牌、系统凭据库 |\n\n## 参考资料\n\n- [PyInstaller 官方手册](https://pyinstaller.org/en/stable/)\n- [Nuitka User Manual](https://nuitka.net/user-documentation/user-manual.html)\n- [Cython：Source Files and Compilation](https://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html)\n\n> 更新核验日期：2026-08-01。工具版本和平台签名要求变化较快，实际发布前应再次核对官方文档。\n"
}
