安全模型
运行时闸门到底检查了什么、为什么"机器不对"和"文件被篡改"这两种报错故意做成一样,以及每个档位诚实的能力边界。
保护不是一个"要么在要么不在"的开关——它是插入到每个受保护模块里的一次运行时检查,那个模块每次被 import 都会跑一遍,完全离线,使用的密钥材料从不离开它所属的设备。
闸门检查什么
受保护代码每次运行时,MagicLock 都会在本地按下面的顺序验证:
- 授权是真的——它由你的账号签发,签名能通过验证。
- 授权仍然有效——没有过期,没有被吊销。
- 设备对得上——这正是该授权(或产物)绑定的那台机器。
- 能力在允许范围内——即将执行的操作在授权允许的范围之内。
- 凭证是新鲜的——一次性凭证排除了截获旧凭证重放的可能。
任何一步失败,受保护代码就不会执行——没有"部分放行"或"尽力而为"这种中间状态。
为什么"机器不对"和"文件被篡改"看起来一样
VaultLockedError(见 API 参考)在两种情况下都会抛出:产物在错误的机器上被打开,以及它的本地状态被篡改过。这是故意设计成这样的——如果区分开这两种情况,就等于泄露了验证失败的"原因",而这正是攻击者探测弱点时最想要的那种信息。不管是哪种情况,报错信息都一样。
防篡改,而不只是"检测"篡改
加密产物是经过认证的,不只是加密——哪怕只翻转一个字节,认证就会在解密开始之前失败。不存在"部分解密一个被改过的文件供你查看"这回事,它只会直接拒绝运行。
每个档位到底能挡住什么
务必看清你在做的是什么取舍:
- 便捷档(
.pya)——挡住随手复制和随手查看源码。应用运行期间,解密后的字节码必然存在于进程内存中;一个足够有动机、带着调试器并且完全控制运行进程的攻击者,理论上可以把它提取出来。这一档要解决的是"别让复制变得毫不费力",而不是对抗内存取证。 - 编译强档(
magiclock build)——完全不出货明文 Python,授权检查在构建期就被自动编织进每一个编译后模块的控制流,而不是集中在一处可以删掉的共享检查背后。它堵上了最简单的绕过方式("直接删掉检查"),把门槛从"读源码"提高到了"逐个模块逆向一个编译后的二进制"。 - 设备绑定——把解密和一个基于本地硬件/系统标识派生出的机器指纹绑在一起。它能挡住机器之间随手复制;它不是硬件安全元件的替代品,一个资源足够充足、完全控制设备的攻击者理论上可能尝试伪造这个指纹。
MagicLock 的目标是让复制、篡改和逆向工程的代价显著提高——而不是宣称任何纯软件保护对一个拥有无限时间、完全控制硬件的攻击者是不可攻破的。如果你的威胁模型需要抵御这个级别的对手,那是硬件级保护要解决的问题。
签名与密钥
授权用 Ed25519 签名,针对你的厂商密钥验证——吊销名单也用同一套签名机制保护,所以一份过期或伪造的吊销名单没法被重放回去"撤销吊销"。验证公钥内嵌在你交付的产物里;用于签名的私钥永远不会离开授权服务器。
另请参阅
- 账号与激活——离线宽限窗口,以及吊销到底影响什么、不影响什么。
- Python API 参考——每种失败模式在你代码里会抛出哪个异常。