主页
文章
登录
登录
注册
忘记密码
反馈
文章
FastAPI 项目使用 PyArmor 外置许可证混淆与授权
FastAPI 项目使用 PyArmor 外置许可证混淆与授权
lyjin
2025-07-29
> Python 3.13.5 > Pyarmor 9.1.8 (trial) ## 一、背景与目标 在向多家企业交付 FastAPI 服务时,我们既要**保护源码**避免泄露,又要**灵活控制授权**(机器绑定 + 到期)。PyArmor 8.5+ 的 **外置许可证(Runtime Key)** 机制可以让我们 **一次混淆代码、多次下发钥匙**,极大降低维护成本。 > **核心思路:** > - **代码包**:一次 `pyarmor gen --outer` 生成,所有客户通用。 > - **授权钥匙**:每台服务器独立生成 `.mcp.lic`(或默认 `pyarmor.rkey`),绑定硬件指纹并设置有效期。 > - **升级 / 续费**:替换钥匙即可,无需重新打包。 --- ## 二、PyArmor 运行原理快速回顾 1. `pyarmor gen` 将每个 `.py` 文件替换为 **加密块 + 引导 stub** 并复制运行时包 `pyarmor_runtime_000000/`。 2. 应用入口先导入 `pyarmor_runtime`,它会 - 读取同目录的外置钥匙文件; - 校验 **Machine ID、到期日、并发数**; - 调用 `pytransform.so` 解密字节码生成 `code object` 并交给 CPython 执行。 3. **Machine ID** 由 PyArmor 通过网卡 MAC、硬盘 SN 等信息自行哈希生成,与系统 `/etc/machine-id` 无关。 4. `-e <天数|日期>` 只精确到「天」;分钟级测试需用外置 Key + 自定义插件实现。 --- ## 三、实操步骤(假设项目顶层包名 app/) ### 1. 环境准备 ```bash python -m venv .venv && source .venv/bin/activate pip install -U pyarmor==9.1.8 # Trial 版即可 pip install -r requirements.txt # FastAPI 等依赖 ``` ### 2. 获取 PyArmor Machine ID ```bash python -m pyarmor.cli.hdinfo # 输出示例:Machine ID: 'm863ce555e8152dd2886df2604e733911' MID="m863ce555e8152dd2886df2604e733911" ``` `python -m pyarmor.cli.hdinfo` 打印的 Machine ID(以 m 开头的 33 位字符串)是 PyArmor 自己计算 的硬件指纹;它不是 Linux 的 `/etc/machine-id` 文件。PyArmor 生成或校验许可证时,只认它计算出的 Machine ID,不读取 `/etc/machine-id`。 **PyArmor 的 Machine ID 从哪来** | 组成字段 | 说明 | | ------------ | ------------ | | 默认 MAC 地址 | hdinfo 会取 第一块网卡 的 MAC,再做 MD5 并加前缀 m | | 硬盘序列号 | 若能读取到固定 SN,会一并参与哈希 | | 主机域名 | localdomain 等信息也可能混入 | | 其它补充 | 如果 MAC/SN 拿不到,PyArmor 会退化到随机字符串导致每次重启都变 ID(常见于 WSL、云主机) | ### 3. 一次混淆代码(外置许可证) ```bash pyarmor gen -r -O build/linux_x64 --outer app ``` - `-r` 递归混淆子包 - `--outer` 让运行时在启动时再加载外置钥匙 ### 4. 生成 180天有效 的授权钥匙 ```bash EXP=$(date -d '+180 days' '+%Y-%m-%d') # 动态计算明天 pyarmor gen key -b "$MID" -e "$EXP" --period 30s -O build/linux_x64/pyarmor_runtime_*/ ``` 生成文件 `build/linux_x64/pyarmor_runtime_000000/pyarmor.rkey` (若已用 `pyarmor cfg outer_keyname=".mcp.lic"` 改名,这里会输出 `.mcp.lic`。) `--period N` 用来给 外置 Key 或内置许可证 加一个 “心跳”: 脚本每 N 个单位(默认 1 小时)自动重新检查授权文件。 - 没设置 --period ⇒ 只在「启动瞬间」做一次校验,之后即使到期、换机器进程也继续跑; - 设置了 --period 60s(或 1m、1h 等)⇒ 运行时会按照设定的周期重新加载 Key,一旦发现到期或指纹不符就抛 PyarmorError 并 立即退出。 | 形式 | 等价 | 说明 | | ------------ | ------------ | ------------ | | --period 1 | --period 1h | 默认单位是 小时 | | --period 60m | --period 1h | 60 分钟 | | --period 3600s | --period 1h | 3 600 秒 | | --period 30s | -- | 半分钟,用于快速测试 | 支持三个单位:s(秒)、m(分钟)、h(小时)。填纯数字就是小时。 ### 5. 启动验证 ```bash cd build/linux_x64 uvicorn app.app:create_app ``` 到期或指纹不符时会抛出 `PyarmorError` 并退出。 --- ## 四、多客户交付流程 | 场景 | 动作 | |------|------| | 新客户部署 | 复制通用 **代码包** + 针对其机器的 `.mcp.lic` | | 续费或延长试用 | 重新 `pyarmor gen key -b <MID> -e <新日期>` 覆盖旧钥匙 | | 跨平台 (Win/macOS/ARM) | 用 `pyarmor gen --platform <target>` 分别打包各平台 | --- ## 五、常见问题与排错 | 症状 | 原因 | 解决 | |------|------|------| | `not this machine` | 用错指纹生成钥匙 | 必须使用 `hdinfo` 打印的 Machine ID | | 每次重启 ID 都变 | 云主机网卡 MAC 不固定 | 绑定自定义 `--bind-mdata` 或固定 MAC | | `missing license key` | 运行时找不到外置钥匙文件 | 确认文件名与 `outer_keyname` 配置一致 | | 跨平台启动失败 | `.so` 架构不匹配 | 重新 `gen --platform` 打包 | --- ## 六、附录:修改钥匙文件名 ```bash pyarmor cfg outer_keyname=".mcp.lic" ``` - 影响 **后续生成** 的运行时代码与钥匙文件名 - 已发布版本:把旧 `pyarmor.rkey` 改名为 `.mcp.lic` 即可继续使用 --- > **到此,FastAPI 项目即可「一份混淆代码、多张授权钥匙」在不同企业服务器安全运行,运维只需替换钥匙文件即可完成续费或迁移。**
分享
×
用手机扫码分享
没有评论
请登陆后评论
新建评论
移除
关闭
提交