如何生成和验证软件许可证密钥?


236

我目前正在开发产品(使用C#开发),该产品可免费下载和安装,但版本非常有限。要访问所有功能,用户必须支付许可费并获得密钥。然后,该密钥将输入到应用程序中以“解锁”完整版本。

由于通常使用这样的许可证密钥,我想知道:

  1. 通常如何解决?
  2. 如何生成密钥,应用程序如何对其进行验证?
  3. 我还应该如何避免让密钥在Internet上发布并被尚未支付许可证的其他人使用(该密钥基本上不是“他们的”密钥)。

我想我也应该以某种方式将密钥绑定到应用程序的版本,以便可以为功能版本中的新密钥收费。

在这种情况下,我还有什么需要考虑的?

Answers:


126

注意:您不能阻止用户进行盗版,而只能让诚实的用户更容易地做正确的事。

假设您不想为每个用户做一个特殊的构建,那么:

  • 为自己生成产品的密钥
  • 取用户名
  • 将用户名,密钥和哈希与(例如)SHA1关联
  • 将SHA1哈希作为字母数字字符串解压缩。这是个人用户的“产品密钥”
  • 在程序内,执行相同的哈希,然后与产品密钥进行比较。如果相等,则确定。

但是,我再说一遍:这不会防止盗版


我最近读到,这种方法在密码学上不是很好。但是这种解决方案已经很弱了(因为软件本身必须在某个地方包含密钥),所以我认为这一发现不会使解决方案在任何程度上失效。

不过,我以为我真的应该提这个;如果您打算从中得到其他东西,请当心。


13
如果程序包含密钥(如上述步骤所示),则对其进行破解很简单
Steven A. Lowe 2010年

2
编辑得更明显;不能过分强调一些基本内容;-)
史蒂文·A·洛

23
使用非对称密码方法(例如RSA)来生成和解码产品密钥,以避免将机密嵌入代码中。
阿米尔·莫吉米

6
我认为在有人入侵您的代码(可能是在汇编级别)以找到您的秘密密钥时,他们可能也在完全绕过您的检查的级别。我认为没有一种安全的注册方法可以使在本地运行该程序的优秀黑客幸免。正如原始评论所说,实际上,所有这些使它比简单地复制文件难上一步。如今,许多游戏已经放弃了版权保护,只是将游戏内容带到了网上,在这种情况下,代码已不在黑客的掌控之下。
JamieB

1
在许可证密钥中包含限制是否很常见?例如,时间限制,并发用户数,要安装的模块等?
卡洛(Carlo)

97

生成许可证密钥的方法有很多,但真正安全的方法很少。遗憾的是,对于公司而言,许可证密钥的价值几乎与真实现金相同。

理想情况下,您希望许可证密钥具有以下属性:

  1. 即使有人完全对您的产品进行反向工程,只有您的公司才能为您的产品生成许可证密钥(根据经验,这将发生)。如果您真的想控制许可,那么对算法进行混淆或在软件中隐藏加密密钥确实是不可能的。如果您的产品成功,那么从发布之日起几天内,就会有人生成密钥生成器。

  2. 许可证密钥只能在一台计算机上使用(或者至少您应该能够非常紧密地控制它)

  3. 许可证密钥应简短且易于在电话上键入或指示。您不希望每个客户都致电技术支持,因为他们不知道密钥是包含“ l”还是“ 1”。您的支持部门将对此表示感谢,您在这方面的费用将会降低。

那么您如何解决这些挑战?

  1. 答案很简单,但在技术上却具有挑战性:使用公钥密码术的数字签名。实际上,您的许可证密钥应该是经过签名的“文档”,其中包含一些有用的数据,并使用公司的私钥进行了签名。签名应该是许可证密钥的一部分。产品应使用相应的公共密钥来验证许可证密钥。这样,即使某人可以完全控制您产品的逻辑,他们也不会生成许可证密钥,因为他们没有私钥。许可证密钥如下所示:BASE32(CONCAT(DATA,PRIVATE_KEY_ENCRYPTED(HASH(DATA))))这里最大的挑战是传统的公钥算法具有较大的签名大小。RSA512具有1024位签名。您不希望许可证密钥包含数百个字符。最强大的方法之一是使用椭圆曲线密码术(精心设计以避免使用现有专利)。相同强度的ECC密钥比RSA密钥短6倍。您可以使用Schnorr数字签名算法之类的算法来进一步减小签名的大小(专利于2008年到期-很好:))

  2. 这可以通过激活产品来实现(Windows是一个很好的例子)。基本上,对于具有有效许可证密钥的客户,您需要生成一些“激活数据”,这是将计算机的硬件ID嵌入为签名数据的签名消息。通常,这是通过Internet完成的,但是只有一次:产品将许可证密钥和计算机硬件ID发送到激活服务器,然后激活服务器将已签名的消息发回(也可以使消息简短易懂)。电话)。从那时起,产品将不会在启动时检查许可证密钥,而是在激活数据方面进行检查,该激活数据需要计算机相同才能进行验证(否则,DATA将有所不同,而数字签名将不会进行验证)。

  3. 好吧,只需从您的键中消除冗余字符,例如“ 1”,“ l”,“ 0”,“ o”。将许可证密钥字符串分成字符组。


8
他们难道不可以编辑软件添加/删除代码以使检查完全跳过吗?
Pacerier,2014年

答案是否为1实质上需要在线激活/停用服务?
丹·W

2
我想指出,这个答案比其他仓促的事情要优越得多。
Erik Aronesty '19

1
@Pacerier许可证密钥可以保护软件公司免受许多伤害。修改exe并不是其中之一。
Erik Aronesty

1
值得注意的是,即使使用非对称密码学私钥/公钥,也可以通过简单地用另一个公钥替换软件中随附的公钥,并使用其相应的私钥对伪造的许可证进行签名来生成伪造的许可证。这就是我们拥有并需要受信任的证书颁发机构BTW的原因,它将公钥绑定到身份。因此,尽管这可能会增加一个循环,但它本身并不能保证#1。
萨卜·阿米尼

76

简单的答案-无论您使用哪种方案,都可以破解。

不要使用旨在防止黑客攻击的系统来惩罚诚实的客户,因为无论如何,黑客都会破解它。

一个简单的哈希码绑定到他们的电子邮件或类似的东西可能就足够了。当人们需要重新安装或更新硬件时,基于硬件的ID总是成为一个问题。

有关此问题的好线程:http : //discuss.joelonsoftware.com/default.asp?biz.5.82298.34


2
同意,您不希望打扰实际购买您产品的用户!(支付百万美元,苹果等)
杰森(Jason

2
微软,苹果等公司可以逃避它的麻烦,因为它们很大,并且提供了很难在其他地方获得的核心产品,或者可以用来强迫人们使用的巨大市场阴影。小型开发人员不能。
帆船2009年

1
不能“破解”发布/私钥签名方案,以为希望运行从发布者网站下载的签名代码的用户(而不是破解软件)产生新的有效密钥。而可以破解散列/对称方案,以产生与无效密钥无法区分的新有效许可证密钥。差异很大。
Erik Aronesty

断开的链接....
stigzler

56

生成密钥时,不要忘记将版本和内部版本号连接到您计算哈希值的字符串。这样一来,就不会有一个钥匙可以解开您曾经发布的所有内容。

astalavista.box.sk中找到一些浮动的密钥或补丁之后,您将知道您成功制作了一些流行的东西,以至于有人不愿破解。麾!


8
“不要忘了将版本和内部版本号连接到您要计算哈希值的字符串上”-但是,当用户更新到次要补丁程序版本时,这不会使密钥中断吗?
thomthom

1
@thomthom然后将最大版本关联到密钥如何?版本概念本身是合理的,并增加了安全性
Marvin Thobejane 2015年

@MarvinThobejane关联一个最大版本,您可以对允许的最大版本进行签名,并使代码对其版本进行一点迭代。但信号符号中不允许> = ops。
Erik Aronesty '19

22

除了已经说过的...。

由于中间语言的问题,任何对.NET应用程序的使用在本质上都是易碎的。.NET代码的简单反汇编将向任何人开放您的产品。他们可以轻松地绕过您的许可代码。

您甚至不能再使用硬件值来创建密钥。虚拟机现在允许某人创建“许可”计算机的映像并在他们选择的任何平台上运行。

如果它是昂贵的软件,那么还有其他解决方案。如果不是这样,请为临时黑客增加足够的难度。并接受一个事实,那就是最终将有未经许可的副本在那里。

如果您的产品很复杂,固有的支持问题将为您提供一些保护。


9
+1用于防止由于虚拟机而导致硬件值下降。
Rubens Mariuzzo 2012年

3
这就是.NET和PE签名的Authenticode的强名称。如果有人对您的库进行了反编译,修改和重建,则不会对其进行签名,并且该应用程序也将无法运行。.NET虚拟机不允许这样做。
Stephen Tunney 2015年

2
签名用于验证您将运行的程序的来源。如果用户不知道原产地是因为他知道原产地已被修改并被破解,则破解者会删除签名,甚至使用自己的签名对其进行签名。签名确实会停止将可信任程序集与不可信任程序集混合在一起。
jesusduarte '16

移动应用程序可用作昂贵软件的陪审团操纵的硬件加密狗....只需使用该应用程序付款,然后在应用程序的安全元素中嵌入签名密钥。那么您可以使用桌面+应用激活...停用其他桌面。在应用程序和/或在线同态计算服务中并置一些关键部分代码区域可以帮助防止琐碎的反编译。
Erik Aronesty '19

12

现在,我们用于生成许可证密钥的C#/ .NET引擎仍保持开源状态:

https://github.com/appsoftware/.NET-Licence-Key-Generator

它基于“部分密钥验证”系统,这意味着只需要将用于生成密钥的密钥子集编译为可分发文件即可。您可以自行创建密钥,因此许可证实施对于您的软件是唯一的。

如上所述,如果您的代码可以反编译,则规避大多数许可系统相对容易。


您愿意做一个使用该产品的教程吗?我发现他们的Wiki有点缺乏。
安东尼·鲁菲诺

如果有帮助的话,该项目现已在GitHub上开源(通过链接编辑答案)。
gb2d

10

我是Cryptolens软件许可平台背后的开发人员之一,并且从14岁起就开始从事许可系统的开发。在此答案中,我根据多年的经验提供了一些技巧。

解决此问题的最佳方法是设置一个许可证密钥服务器,应用程序的每个实例都将调用该服务器以验证许可证密钥。

许可证密钥服务器的好处

许可证密钥服务器的优点在于:

  1. 您始终可以立即更新或阻止许可证密钥。
  2. 每个许可证密钥可以锁定到一定数量的计算机上(这有助于防止用户在线发布许可证密钥以供其他人使用)。

注意事项

尽管在线验证许可证可以使您更好地控制应用程序的每个实例,但是互联网连接并不总是存在(特别是如果您针对大型企业),因此我们需要另一种执行许可证密钥验证的方法。

解决方案是始终使用RSA或ECC之类的公钥密码系统对服务器的许可证密钥响应进行签名(如果计划在嵌入式系统上运行,则可能会更好)。您的应用程序应仅具有公共密钥以验证许可证密钥响应。

因此,如果没有互联网连接,则可以改用以前的许可证密钥响应。确保在响应中同时存储日期机器标识符,并检查日期是否太旧(例如,您允许用户最多30天离线等),并且许可证密钥响应属于正确的设备。

请注意,即使您已连接到Internet,也应始终检查许可证密钥响应证书,以确保自从离开服务器以来未对其进行更改(即使您的API仍要这样做,也必须这样做)。许可证密钥服务器使用https)

保护秘密算法

大多数.NET应用程序可以很容易地进行逆向工程(Microsoft提供了一个双汇编程序来获取IL代码,有些商业产品甚至可以检索C#等源代码)。当然,您始终可以混淆代码,但是它永远不会100%安全。

在大多数情况下,任何软件许可解决方案的目的都是为了帮助诚实的人诚实(即,愿意付款的诚实用户不要在试用期满后忘记付款,等等)。

但是,您可能仍然有一些绝对不希望泄漏给公众的代码(例如,预测股票价格的算法等)。在这种情况下,唯一的方法是创建一个API端点,您的应用程序将在每次执行该方法时调用该端点。它需要Internet连接,但可以确保客户端计算机永远不会执行您的密码。

实作

如果您不想自己实现所有功能,建议您看一下本教程Cryptolens的一部分)


关于将保存的许可证密钥限制为不能太旧的一个问题:由于PC可能未连接到Internet,因此可以始终将其日期和时间改回为保持相同的有效日期吗?
阿米尔·马赫迪·纳西里

用户不能通过在Windows中定义回送主机来绕过在线许可证服务器吗?我已经看到很多应用程序是那样的盗版,Resharper和Matlab是我记得的应用程序。
阿米尔·马赫迪·纳西里

1
@AmirMahdiNassiri对于问题1:如果PC永久脱机,则可以使用实时时钟(RTC)加密狗作为时间的可信来源。对于问题2:由于响应是使用供应商的私钥签名的(并已通过应用程序内的公钥验证),所以对手需要重新签名文件,而无需知道私钥,在撰写本文时,私钥是2048位RSA密钥无法使用。
Artem

7

我过去曾经使用过Crypkey。它是众多可用产品之一。

您只能使用任何许可方案保护软件。


6

我不知道你想多精打细算

但我相信.net可以访问硬盘驱动器序列号。

您可以让程序向您发送该信息以及其他信息(例如nic的用户名和mac地址)

您可以据此计算出代码,然后将其通过电子邮件发送给密钥。

拥有钥匙后,他们将阻止他们切换机器。


4
并防止它们取代其他响声中的死HD,从而导致沮丧。不幸的是,没有简单的答案,您需要在信任与基本许可机制之间取得平衡。
schooner,2009年

作为软件工程师工作了多年的产品使用了高清序列号,对于那些知道如何更新它的人来说,这完全是不安全的。
奥登

我的意思是将此数字与其他内容(mac地址,FQDN)一起使用,可能会将它们全部放入一个哈希中。关键是要比从一开始对软件进行逆向工程和删除检查要困难得多,因为这总是一个选择。
Crash893 '16

4

完成您要求的所有操作的唯一方法是要求Internet访问和服务器验证。应用程序需要使用密钥登录服务器,然后您需要存储会话详细信息,例如IP地址。这将防止密钥在多台不同的机器上使用。这通常在应用程序用户中不太流行,除非这是一个非常昂贵和复杂的应用程序,否则不值得。

您可能只拥有该应用程序的许可证密钥,然后检查客户端密钥是否正确,但是很容易将该密钥分发给其他用户,并且通过反编译器可以生成新密钥。


5
我在一家使用基于Internet的许可计划的公司工作。每当程序启动时,它都会在线进行验证,我认为该公司在其基础架构和开发人员的许可解决方案上花费的资金要多于盗版所造成的损失(这是一种利基产品)。
杰森

3
此外,技术支持成本巨大。很多时候,很多时候用户会合法地使用另一台计算机来尝试和运行该软件,但是散列是不同的,这导致了大量的技术支持。简而言之,大篷车所说的-不要惩罚诚实的用户。
杰森

1
似乎您的公司每次都要求在启动时进行验证,所以有点发狂。
jugg1es

@Jason,嗯,他们应该提高产品的价格。
Pacerier,2014年

1
@Pacerier:答案错误。
Lightness Races in Orbit

4

我已经在公司的软件(C#.net)上实现了基于Internet的一次性激活,该激活需要一个许可证密钥,该许可证密钥指向存储在服务器数据库中的许可证。该软件使用密钥访问服务器,并获得许可信息,然后使用从客户端计算机上的某些变量(CPUID和其他不会经常更改的内容的组合)生成的RSA密钥在本地对许可证信息进行加密,然后将其存储在注册表。

它需要一些服务器端编码,但是对我们来说确实非常有效,当我们扩展到基于浏览器的软件时,我能够使用相同的系统。它还为您的销售人员提供了有关谁在何时何地使用该软件的重要信息。任何仅在本地处理的许可系统都完全容易受到利用,尤其是.NET中的反射。但是,就像其他人所说的那样,没有系统是完全安全的。

我认为,如果您不使用基于Web的许可,则根本没有保护软件的真正意义。由于DRM可能引起头痛,这对实际为此付出代价的用户而言是不公平的。


1
但是Web许可的主要问题是许可服务成为DDoS攻击的主要目标。这会使服务瘫痪或增加云成本。
afk5min 2014年

4
这就像在说建立一个网站毫无意义,因为它很容易受到DDoS攻击……
jugg1es 2014年

@ jugg1es他在评论中没有说“没有意义”。他只是指出了应该考虑的一个漏洞这一事实。
丹·贝查德

并且支票仍然可以在客户端中删除。没有支票,没有基于网络的许可...
azarai 2014年

1
实际的应用程序代码是指“必填信息”吗?运行该应用程序所需的代码?否则,我认为它仍然会导致在那些代码中调用isLicensed检查方法。
azarai 2014年

4

我坚信,只有基于公钥加密的许可系统才是正确的方法,因为您不必在源代码中包含生成许可证所需的必要信息。

过去,我已经多次使用Treek的许可库,因为它满足了这一要求并提供了非常优惠的价格。它对最终用户及其本身使用相同的许可证保护,直到现在为止还没有人破解。您还可以在网站上找到一些好的技巧,以避免盗版和破解。


公钥密码术是否需要使用在线激活服务?我的意思是,如果它不在源代码中(我想您也指可执行文件),它还能在哪里?
丹·W

不,您不必使用在线激活服务。您可以完全脱机生成许可证文件。
panpernicek

关键在于,实际上您只将公共密钥放置在代码中,而不能用于生成许可证。仅用于其验证。
panpernicek

3

就像其他一些提到的一样,我是默认情况下对客户怀有敌意的巨大反对者 -许可行业众所周知。因此,我将为您的问题扩展一个好的解决方案,该解决方案还提供良好的客户体验

首先,您提到您有一个软件的“有限”版本,用于尝试将客户转换为“升级”以获得其他功能。因此,您要查找的是产品的功能许可证,例如,客户可以购买功能X功能Y的许可证。

我在构建Keygen时就考虑到了这种类型的许可。Keygen是许可的REST API,可让您管理用户帐户,许可证并跟踪计算机的使用/关联。

我要做的是设置2种许可类型(Keygen中的一种策略),其中一种是有限免费版本的基本策略,另一种是付费版本的策略。

我不确定您使用的是什么付款方式,但假设您使用的是诸如Stripe(如今相当标准)之类的东西,可以提供webhooks。Keygen也有webhooks(无论您是否使用它,所有这些仍然适用)。您可以集成Keygen来使用双方的Webhooks与您的付款提供商进行对话(请考虑:customer.created->为客户创建基本许可证,license.created->为新许可证向客户收费)。

因此,通过利用Webhook,我们可以自动为新客户创建许可证。那么,应用程序内部的许可证验证又如何呢?这可以通过多种方式来完成,但是最流行的方式是要求客户在输入字段中输入长许可证密钥,然后您可以进行验证;我认为这是在您的应用程序中处理许可证验证的糟糕方法。

我为什么这么认为?首先,您要求客户输入一个冗长的机器使用许可密钥,其次,您需要您和您的客户跟踪所述繁琐的许可密钥

好吧,那有什么选择呢?我认为最好的选择是做所有您的客户都习惯的事情:允许他们使用电子邮件/密码为您的产品创建一个帐户。然后,您可以将其所有许可证和计算机与该帐户关联。因此,他们现在无需输入许可证密钥,只需使用其凭据登录即可。

那给你什么好处?首先,它消除了您和您​​的客户跟踪许可证密钥的需要,因为所有这些都在其用户帐户内进行了后台处理,最重要的是:您现在可以为客户提供自助式许可证和机器激活!即,由于他们的所有许可证和计算机都与他们的用户帐户相关联,因此当他们在无法识别的计算机上启动您的应用程序时,您可以提示他们购买许可证。

现在进入许可证验证:每当客户使用其电子邮件/密码登录到您的应用程序时,您都可以查询其拥有的许可证的用户帐户,以确定他们是否可以使用feature-Xfeature-Y。而且,由于您的应用程序现在是自助服务,因此您可以允许客户直接在应用程序内购买其他功能!

因此,我们在许可系统中引入了大量自动化功能,我们可以许可单个功能(即有限版与完整版),我们为客户提供了出色的 UX,并且还减轻了最大的原因之一对于支持请求:许可证密钥恢复。

无论如何,这很长,但希望可以对某人有所帮助!


无法想象在任何企业开发情况下DLL都会像这样被许可。例如,考虑一下自动构建和部署方案。或者简单地将此步骤添加到设置开发人员计算机通常需要的许多步骤中。对我来说,必须预先颁发许可证密钥,而不是基于单个计算机,这是实用的
DvS

2

不能完全防止软件盗版。您可以防止随意的盗版,这就是所有许可解决方案的作用。

如果要防止重复使用许可证密钥,最好使用节点(计算机)锁定的许可证。我的软件已经使用Cryptlex大约一年了。它也有免费计划,因此,如果您不希望有太多客户,可以免费使用它。


2

您可以使用免费的第三方解决方案为您处理此问题,例如Quantum-Key.Net。它是免费的,并可以通过为您创建的网络销售页面通过Paypal处理付款,通过电子邮件进行密钥发布并将密钥使用锁定到特定计算机上。防止盗版。

您还应该注意对代码进行混淆/加密,否则可以使用De4dot和.NetReflector等软件轻松对其进行反向工程。ConfuserEx是一个很好的免费代码混淆器,它快速,易于使用并且比昂贵的替代方案更有效。

您应该通过De4Dot和.NetReflector运行完成的软件,以对其进行反向工程,并查看破解者在做同样的事情时会看到什么,并确保您没有遗漏或掩盖任何重要的代码。

您的软件仍然可以破解,但对于随意的破解者来说,将其推迟可能就足够了,这些简单的步骤也将阻止提取和重复使用您的代码。

https://quantum-key.net

如何使用ConfuserEx?

https://github.com/0xd4d/de4dot

https://www.red-gate.com/dynamic/products/dotnet-development/reflector/download

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.