【问题标题】:Serial generation with PHP使用 PHP 进行串行生成
【发布时间】:2011-04-10 21:56:26
【问题描述】:

在我作为 PHP 程序员和 C# 编程初学者的整个过程中,我一直想知道生成独特连续剧的最佳方法,例如 Microsoft Office 和 Microsoft 操作系统的做法。

有没有人对如何处理这个问题有很好的指导,比如生成唯一序列的重要因素是什么,防止重复等等。关于如何创建/验证它们的小例子。

这是我所说的 RFC:https://www.rfc-editor.org/rfc/rfc1982

【问题讨论】:

    标签: php license-key


    【解决方案1】:

    我不确定你想要什么,但有 http://www.php.net/manual/en/function.uniqid.php 可以创建唯一标识符。

    如果您对它们的创建方式更感兴趣,我建议您查看 PHP 源代码以了解 uniqid 是如何实现的。

    【讨论】:

    • uniqid 是完全可以预测的。实际上,它只是生成它的微时间的代表。这绝不是随机的。
    【解决方案2】:

    需要更多信息。您是想在购买游戏时创建一个序列号,还是想为一个唯一的用户 ID 创建一个序列号。

    序列号是否需要存储过期时间/日期等信息?

    @nikic - 所有 rand 的使用时间作为启动随机生成器的基础。这就是国防部使用熔岩灯的原因。他们有一整个房间专门放熔岩灯,并用激光照射它们以随机创建一个独特的钥匙。

    已编辑:

    那么您需要生效的是您的 C# 应用程序将使用哪种方法与您的站点进行通信。

    您需要使用 php 创建一个密钥并将其存储在数据库中,以便 C# 可以确认序列号是正确的。

    然后您需要确定 PHP 是否会返回另一个值,以便 C# 应用程序知道密钥是否经过身份验证。

    我在粘贴中所做的是创建一个公钥和私钥。公钥将提供给用户以验证产品。当他们验证产品或登录系统时,将根据数据库检查公钥,返回值将是私钥。在与我的 C# 程序的所有交互过程中,如果用户需要检查更新或从我的服务器提取信息,私钥将被添加到对服务器的查询中,以确认最终用户是合法的。

    我也使用的另一种方法是上述方法,但添加了额外的检查以确认用户没有共享密钥。 C# 应用程序将获取计算机中处理器的序列号,并在注册应用程序后将其保存到我的数据库中。然后,如果其他人尝试使用相同的公钥但处理器的序列号不同来注册产品,则会引发错误,他们需要联系支持。您可以这样做以允许 5 个不同的机器 ID 或您想要多少个。

    创建注册密钥非常简单,因为您实际上只需要创建一个带有偏移量的随机字符串(例如用户名)。

    但是,您也可以根据某人提供的名称或公司名称创建注册密钥,并将该算法添加到您的 C# 程序中。这样做的缺点是 C# 源代码可以很容易地反编译,可以找到该算法来轻松创建注册代码,而无需有人实际为产品付费。通过添加执行身份验证的服务器,某人生成自己的序列密钥变得更加困难。

    【讨论】:

    • 假设我有一个产品,例如一个应用程序,这个应用程序需要一个串行系统,我想在 PHP 中生成一个可以在 C# 中检查和验证的串行,我必须考虑哪些因素应用到脚本中,以便能够生成和验证 A 密钥,而不管解释器是什么。
    • 我编辑了我的答案,以展示我在粘贴中所做的一些示例。
    【解决方案3】:

    如果您的应用程序有一个与服务器的连接,这很简单,只需生成随机令牌,将它们存储在数据库中,并要求应用程序在运行前与服务器进行核对即可。然而,一些客户可能会发现这个要求是不可接受的。 (我个人永远不会购买任何需要互联网激活的软件。我想购买软件,而不是租用它。)

    对于具有真实性可检查性且无需连接回服务器的密钥:

    1. 在服务器上,生成一个随机的唯一令牌。

    2. 使用公钥加密方案(例如RSA)使用对服务器保密的私钥对令牌进行签名。

    3. 使用一些二进制到文本的方案(例如,base64,或仅使用2-9A-KMNP-Z 符号以实现更安全的打字)将唯一令牌和签名一起编码。编码的组合是您的密钥或序列号。

    4. 在应用程序的每个副本中嵌入与服务器私钥匹配的公钥,并在安装时让应用程序提示输入密钥。它可以拆分唯一令牌和签名,并使用公钥验证签名对该令牌是否有效。

    这种方法需要您将一些加密库与您的软件捆绑在一起,并且大多数算法都使用相当长的签名,以确保安全,这会使您输入序列号非常繁琐。如果您希望用户复制和粘贴也可以数字。

    由于这些原因,许多软件包使用安全性较低的密钥验证方案,其中检查算法完全内置在客户端中。这可能是一个哈希,例如。序列的最后四个十六进制数字必须与序列其余部分的 SHA1 哈希的最低两个字节与“秘密”密钥相匹配。但是,由于密钥必须捆绑在应用程序中,黑客有可能查看应用程序代码并提取“秘密”密钥,从而允许他们编写自己的密钥生成器。

    这就是为什么对于某些程序,您会看到“keygens”可用:该应用程序使用了一种安全性较低的检查算法,该算法在应用程序中留下了足够的信息,以允许破解者重现密钥制作过程。对于基于公钥加密或互联网激活的更安全设置的程序,您通常会看到应用程序的“破解”版本,其中检查代码已被更改/删除。

    ...这表明无论你做什么,你仍然无法做到诚实。所以不用太担心。

    【讨论】:

    • 完美,正是我正在寻找的信息类型 :),很好的阅读。 +1
    • :-/这正是我所说的。
    【解决方案4】:

    如果您想集中创建随机序列号,只需从数字和字母数组中随机获取就足够了。每次使用mt_rand(0, count($poolArray)) 获取一个新索引,然后将该字符添加到您的序列中,直到您说出其中的 12 个。

    从如此大的池中随机生成它们(26 个字母 + 10 位数字)几乎可以确保您没有重复,但您始终可以在存储新的之前检查现有的。

    如果您有 36 个可能的字符,并从其中随机选择 12 个来制作连续剧,则为 36*36*36*...*36 = 36^12 = 4738381338321616896 个可能的字符串。

    $pool = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $countPool = strlen($pool) - 1;
    $totalChars = 12;
    
    $serial = '' ;
    for ($i = 0 ; $i < $totalChars ; $i++) {
        $currIndex = mt_rand(0, $countPool) ;
        $currChar = $pool[$currIndex] ;
        $serial .= $currChar ;
    }
    

    将它们与您的代码一起分发或让您的程序检查有效序列是另一个问题。

    【讨论】:

    • 对不起,为什么 count($pool) 给我结果 101000100100 而如果我明确分配 35,它会工作 3UNPWR3GWHQP,如果我分配 36,它会使用统一偏移量
    • @yolapop 你是绝对正确的。我的意思是把 $pool 写成一个数组,但不知何故最终把它写成了一个字符串。将其视为一个数组,并且该方法有效。
    【解决方案5】:

    这是我们的解决方案。它根据有效的 IPv4、Userid(或任何有意义的整数)或文本字符串生成具有可配置大小/长度和可选后缀的密钥。它还避免了标准结果中的歧义字符(i,1,l,0,o,O)。

    我们在许可证中附加用户 ID,稍后可以将该部分转换回 base10 整数,并检查它是否对使用许可证的用户帐户有效。

    $license = generate_license();
    // YF6G2-HJQEZ-8JZKY-8C8ZN
    
    $license = generate_license(123456);
    // ZJK82N-8GA5AR-ZSPQVX-2N9C
    
    $license = generate_license($_SERVER['REMOTE_ADDR']);
    // M9H7FP-996BNB-77Y9KW-ARUP4
    
    $license = generate_license('my text suffix');
    // Q98K2F-THAZWG-HJ8R56-MY-TEXT-SUFFIX
    

    我们会在创建时检查数据库中的唯一性,但将 IP/用户 ID 与随机性结合使用,重复的可能性几乎为零。

    /**
    * Generate a License Key.
    * Optional Suffix can be an integer or valid IPv4, either of which is converted to Base36 equivalent
    * If Suffix is neither Numeric or IPv4, the string itself is appended
    *
    * @param   string  $suffix Append this to generated Key.
    * @return  string
    */
    function generate_license($suffix = null) {
        // Default tokens contain no "ambiguous" characters: 1,i,0,o
        if(isset($suffix)){
            // Fewer segments if appending suffix
            $num_segments = 3;
            $segment_chars = 6;
        }else{
            $num_segments = 4;
            $segment_chars = 5;
        }
        $tokens = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
        $license_string = '';
        // Build Default License String
        for ($i = 0; $i < $num_segments; $i++) {
            $segment = '';
            for ($j = 0; $j < $segment_chars; $j++) {
                $segment .= $tokens[rand(0, strlen($tokens)-1)];
            }
            $license_string .= $segment;
            if ($i < ($num_segments - 1)) {
                $license_string .= '-';
            }
        }
        // If provided, convert Suffix
        if(isset($suffix)){
            if(is_numeric($suffix)) {   // Userid provided
                $license_string .= '-'.strtoupper(base_convert($suffix,10,36));
            }else{
                $long = sprintf("%u\n", ip2long($suffix),true);
                if($suffix === long2ip($long) ) {
                    $license_string .= '-'.strtoupper(base_convert($long,10,36));
                }else{
                    $license_string .= '-'.strtoupper(str_ireplace(' ','-',$suffix));
                }
            }
        }
        return $license_string;
    }
    

    【讨论】:

    • 可以分享一下验证功能吗?
    【解决方案6】:

    我的解决方案

    implode( '-', str_split( substr( strtoupper( md5( time() . rand( 1000, 9999 ) ) ), 0, 20 ), 4 ) );
    

    【讨论】:

    • 这很优雅!
    • 好!给定序列,你能解码回日期吗?
    • @Mr.Web 否,因为 md5 哈希函数几乎不可能反转
    猜你喜欢
    • 2012-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多