keygen 这套软件许可服务是怎么设计的
之前研究了一下 keygen(GitHub 上 keygen-sh/keygen-api,一个开源的软件许可服务),想搞清楚工业级的软件授权到底是怎么组织的。看完最大的感受是,它早就不是那种「写个算法、算出一串序列号、客户端拿同样算法校验」的老路子了——那种算法只要被逆出来就全军覆没。keygen 把授权拆成了一套类似图模型的东西在服务端动态管。
整个体系围绕三个东西转:策略(Policy)、许可证(License)、设备(Machine)。策略是规则模板,比如「能激活 3 台机器、有效期一年、每 30 天必须联网一次」;许可证是卖给用户的实体,绑在某个策略上;设备是许可证真正消耗的额度,每激活一台就建一个 Machine 节点、扣一个名额。这套拆法把「卖了多少份」「每份能绑几台」「谁在用」分得很干净,加规则改策略就行,不用动许可证本身。
离线验签靠非对称加密
我觉得这是它最核心的一手。光靠联网请求校验有个致命问题:破解者本地起一个假服务器(mock),把你客户端的请求全拦下来返回「合法」,校验就形同虚设。keygen 的做法是服务端用非对称加密(Ed25519)的私钥给许可证数据签名,客户端只内置公钥。这样它支持完全离线校验——只要签名验得过、数据没被改过,就认。私钥一直在服务端,客户端 mock 再像也没用,因为它签不出合法的签名。
这点其实跟自己做 JWT 授权是一个思路:私钥签、公钥验,把信任根钉在密钥上而不是网络上。
在线激活是把设备和许可证绑死
用户拿到 key 之后在软件里填,客户端带着 key 和本机的硬件指纹去调 validate 接口。服务端查这个 key 合不合法、过没过期,没问题而且是新设备的话,就在后台给它建一个 Machine 节点、扣名额,然后返回一个短期有效的 token。指纹这东西是用来防「一码多绑」的——同一份 key 想在第十台机器上激活,名额不够就拒掉。
运行期间还有心跳:隔几天客户端回来打一次卡,策略里配了心跳的话,超时没报到,这台设备在服务端就被标记失效,下次得重新联网。这条主要是防退款之后继续用、以及及时回收已经不用的授权。
断网环境走文件换码
真正麻烦的是机房、内网这种完全连不上外网的场景。keygen 给的是一套「文件换码」流程:断网机器上软件导出一个带本机指纹的请求文件;用户把它拷到能上网的机器、传到官网;服务端校验后用私钥签一个许可证凭证文件;用户再把它拷回断网机器导入,客户端拿内置公钥验签、比对指纹,过了就离线解锁。
绕了一圈,离线模式下信任还是落在「私钥签名 + 公钥验签 + 设备指纹」这三件套上,联网只是换个地方做这件事。
研究下来其实就一条主线:keygen 把密码学、设备指纹、并发名额、过期控制这些东西,解耦成了一套干净的 RESTful API。开发者不用自己在数据库里写一堆授权判断,客户端要么调它的接口、要么本地拿公钥验签,就能搭出一套还算像样的授权体系。它当然不是无敌的——私钥泄露、客户端被深入逆向都一样会破,但作为「许可即服务」的基础设施,这套抽象确实把脏活都收走了。
