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

像这样使用许可密钥是很常见的,我想知道:

这个问题通常是怎么解决的? 如何生成密钥以及应用程序如何验证密钥? 我怎样才能避免一个密钥被发布在互联网上,并被其他没有支付许可证的人使用(一个基本上不是“他们的”密钥)。

我想我还应该以某种方式将密钥绑定到应用程序的版本,这样就有可能在功能版本中对新密钥收费。

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


我以前用过Crypkey。这是许多可用的之一。

使用任何许可方案,您只能在一定程度上保护软件。


简单的答案-无论你使用什么方案都可以被破解。

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

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

关于这个问题的好帖子: http://discuss.joelonsoftware.com/default.asp?biz.5.82298.34


要做到你所要求的一切,唯一的方法就是要求互联网接入和服务器验证。应用程序需要使用密钥登录到服务器,然后需要存储会话详细信息,如IP地址。这将防止密钥在多台不同的机器上使用。这通常不太受应用程序用户的欢迎,除非这是一个非常昂贵和复杂的应用程序,否则不值得这样做。

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


警告:你不能阻止用户盗版,只能让诚实的用户更容易做正确的事情。

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

为产品生成一个密钥 取用户名 使用(例如)SHA1连接用户名、密钥和散列 将SHA1散列解压缩为字母数字字符串。这是个人用户的“产品密钥” 在程序中,执行相同的散列,并与产品密钥进行比较。如果相等,好的。

但是,我再重复一遍:这并不能阻止盗版


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

只是觉得我真的应该提一下;如果您打算从这里推导出其他东西,请小心。


在生成密钥时,不要忘记将版本和构建号连接到计算散列的字符串上。这样就不会有一把钥匙能打开你释放的所有东西。

当你在astalavista.box.sk中找到一些密钥或补丁后,你就会知道你成功地让某些东西变得流行,以至于有人费心去破解。喜乐!


我不知道你想说得多详细

但我相信。net可以访问硬盘序列号。

你可以让程序把它和其他东西(比如网卡的用户名和MAC地址)发送给你

你在此基础上计算出一个代码,然后把密钥发邮件给他们。

他们会阻止他们在拿到钥匙后换机器。


除了已经说过的....

由于中间语言的问题,. net应用程序的任何使用本质上都是容易被破坏的。对. net代码进行简单的反汇编就可以向任何人打开您的产品。他们可以很容易地绕过你的授权代码。

你甚至不能再使用硬件值来创建键了。虚拟机现在允许人们创建一个“许可”机器的映像,并在他们选择的任何平台上运行它。

如果软件价格昂贵,还有其他解决方案。如果不是,那就给普通黑客制造足够的难度。接受这个事实,即最终会有未授权的副本出现。

如果你的产品很复杂,固有的支持问题将为你创造一些保护。


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

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

Only your company should be able to generate license keys for your products, even if someone completely reverse engineers your products (which WILL happen, I speak from experience). Obfuscating the algorithm or hiding an encryption key within your software is really out of the question if you are serious about controlling licensing. If your product is successful, someone will make a key generator in a matter of days from release. A license key should be useable on only one computer (or at least you should be able to control this very tightly) A license key should be short and easy to type or dictate over the phone. You don't want every customer calling the technical support because they don't understand if the key contains a "l" or a "1". Your support department would thank you for this, and you will have lower costs in this area.

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

The answer is simple but technically challenging: digital signatures using public key cryptography. Your license keys should be in fact signed "documents", containing some useful data, signed with your company's private key. The signatures should be part of the license key. The product should validate the license keys with the corresponding public key. This way, even if someone has full access to your product's logic, they cannot generate license keys because they don't have the private key. A license key would look like this: BASE32(CONCAT(DATA, PRIVATE_KEY_ENCRYPTED(HASH(DATA)))) The biggest challenge here is that the classical public key algorithms have large signature sizes. RSA512 has an 1024-bit signature. You don't want your license keys to have hundreds of characters. One of the most powerful approaches is to use elliptic curve cryptography (with careful implementations to avoid the existing patents). ECC keys are like 6 times shorter than RSA keys, for the same strength. You can further reduce the signature sizes using algorithms like the Schnorr digital signature algorithm (patent expired in 2008 - good :) ) This is achievable by product activation (Windows is a good example). Basically, for a customer with a valid license key, you need to generate some "activation data" which is a signed message embedding the computer's hardware id as the signed data. This is usually done over the internet, but only ONCE: the product sends the license key and the computer hardware id to an activation server, and the activation server sends back the signed message (which can also be made short and easy to dictate over the phone). From that moment on, the product does not check the license key at startup, but the activation data, which needs the computer to be the same in order to validate (otherwise, the DATA would be different and the digital signature would not validate). Note that the activation data checking do not require verification over the Internet: it is sufficient to verify the digital signature of the activation data with the public key already embedded in the product. Well, just eliminate redundant characters like "1", "l", "0", "o" from your keys. Split the license key string into groups of characters.


我们用来生成许可证密钥的c# / .NET引擎现在是开源的:

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

它基于“部分密钥验证”系统,这意味着只有用于生成密钥的密钥子集必须编译到您的分布式文件中。您自己创建密钥,因此许可证实现对于您的软件是惟一的。

如上所述,如果您的代码可以反编译,那么绕过大多数许可系统就相对容易。


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

它需要一些服务器端编码,但它对我们来说工作得非常好,当我们扩展到基于浏览器的软件时,我能够使用相同的系统。它也给你的销售人员提供了关于谁,在哪里,什么时候使用软件的很好的信息。任何只在本地处理的许可系统都很容易被利用,特别是在。net中反射时。但是,正如其他人所说,没有一个系统是完全安全的。

在我看来,如果你不使用基于网络的授权,保护软件就没有任何意义。由于数字版权管理可能引起的头痛,这对已经为此付费的用户来说是不公平的。


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

在过去,我曾多次使用Treek的授权库,因为它满足了这一要求,并提供了非常好的价格。它对终端用户和自身使用相同的许可证保护,直到现在还没有人破解它。你也可以在网站上找到避免盗版和破解的好建议。


你可以使用免费的第三方解决方案来解决这个问题,比如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


我是Cryptolens软件授权平台背后的开发人员之一,从14岁开始就一直在开发授权系统。在这个回答中,我根据多年来的经验总结了一些建议。

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

许可证密钥服务器的好处

使用许可密钥服务器的优点是:

您可以随时更新或阻止许可证密钥立即生效。 每个许可密钥可以被锁定到一定数量的机器上(这有助于防止用户在线发布许可密钥供其他人使用)。

注意事项

虽然在线验证许可证可以让您更好地控制应用程序的每个实例,但internet连接并不总是存在(特别是如果您的目标是大型企业),因此我们需要另一种方式来执行许可证密钥验证。

解决方案是始终使用公钥加密系统(如RSA或ECC)对来自服务器的许可密钥响应进行签名(如果计划在嵌入式系统上运行,可能更好)。您的应用程序应该只有用于验证许可密钥响应的公钥。

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

请注意,您应该始终检查许可密钥响应的证书,即使您连接到internet),以确保它在离开服务器后没有被更改(即使您的API到许可密钥服务器使用https,这仍然必须完成)。

保护秘密算法

大多数。net应用程序都可以很容易地进行反向工程(微软提供了一个反汇编程序来获得IL代码,一些商业产品甚至可以检索源代码,例如。c#)。当然,您总是可以混淆代码,但它永远不会是100%安全的。

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

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

实现

如果你不想自己实现所有的东西,我建议你看看这个教程(Cryptolens的一部分)


我通过将我的程序与一个不和谐的服务器连接来解决这个问题,它在一个特定的聊天中检查用户输入的产品密钥是否存在并且仍然有效。通过这种方式获得产品密钥,用户将被迫破解不和谐,这是非常困难的。


我知道这是一个老问题,但我在为我的一个应用程序重新编写许可流程时引用了这个问题。

在阅读了大量的意见并依靠过去的许可代码经验后,我想出了这个过程。

public static class LicenseGenerator
{
    private static string validChars = "ACEFHJKMNPRSTUVWXYZ234579";
    private static Random rnd = new Random(Guid.NewGuid().GetHashCode());

    /// <summary>
    /// Generate a license code
    /// </summary>
    /// <param name="length">length of each phrase</param>
    /// <param name="number">number of phrases separated by a '-'</param>
    /// <returns></returns>
    public static string GetNewCode(int length, int number)
    {
        string license = string.Empty;

        for (int numberOfPhrases = 0; numberOfPhrases < number; numberOfPhrases++)
        {
            license += getPhrase(length);
            if (numberOfPhrases < number)
                license += "-";
        }

        return license.TrimEnd('-');
    }

    /// <summary>
    /// generate a phrase
    /// </summary>
    /// <param name="length">length of phrase</param>
    /// <returns></returns>
    private static string getPhrase(int length)
    { 
        string phrase = string.Empty;

        for (int loop = 0; loop < length; loop++)
        {
            phrase += validChars[rnd.Next(validChars.Length)];
        }

        return phrase;
    }
}

你真的不想提供一个有相似字母的代码;当最终用户输入时,它会造成混乱。像6和G, B和8,L, I和1。当然,如果你真的想要它们,你可以随时把它们加回来……上面的代码将使用“validChars”中的字符生成类似xxxx-xxxx-xxxx-xxxx的许可证。调用GetNewCode(4,4)将返回与上面类似的代码。

我使用Azure函数注册然后验证代码。当我的应用程序注册代码时,它会生成一个加密散列,其中包含安装、设备和/或用户独有的内容。它被提供给注册函数,并与密钥一起存储在Azure的DB中。

验证重新生成密钥,并向其提供许可代码、IP地址(在我的例子中,IP地址不会改变,如果改变了,那么无论如何都需要更新)和重新生成的散列,然后Azure函数在应用程序获得许可时返回。我确实在他们的服务器上存储了一个“临时”密钥,允许应用运行一段时间而不返回。

当然,我的应用程序必须在网络上,它的工作无论如何。

因此,最终结果是一个供最终用户输入的简单密钥,以及在后端管理许可证的简单流程。如果需要,我还可以使许可证无效。