12

PHP プログラマーおよび C# プログラミングの初心者としての日々を通じて、Microsoft Office や Microsoft オペレーティング システムのように、独自のシリアル番号を生成する最善の方法を常に考えていました。

ユニークなシリアルを生成する上で重要な要素は何か、重複を防ぐなど、これを処理する方法についての良いガイドはありますか?それらを作成/検証する方法の小さな例.

私が話している RFC は次のとおりです: https://www.rfc-editor.org/rfc/rfc1982

4

6 に答える 6

24

これが私たちのソリューションです。有効な 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;
}
于 2015-04-01T16:51:00.607 に答える
22

アプリケーションがサーバーに戻る接続を持っている場合、それは簡単です。ランダムなトークンを生成し、それらをデータベースに保存し、アプリケーションが実行前にサーバーにチェックバックすることを要求します。ただし、一部のお客様は、この要件を受け入れられない場合があります。(個人的には、インターネットのアクティベーションが必要なソフトウェアを購入することはありません。ソフトウェアをレンタルするのではなく、購入したいのです。)

サーバーへの接続を必要とせずに真正性をチェックできるキーの場合:

  1. サーバーで、ランダムな一意のトークンを生成します。

  2. 公開鍵暗号方式 (例: RSA ) を使用して、サーバーに対して秘密にされている秘密鍵でトークンに署名します。

  3. バイナリからテキストへのスキームを使用して、一意のトークンと署名を一緒にエンコードします (たとえば、base64、または2-9A-KMNP-Zより安全な入力可能性のためにシンボルを使用するだけです)。エンコードされた組み合わせがキーまたはシリアルです。

  4. サーバーの秘密鍵と一致する公開鍵をアプリケーションの各コピーに埋め込み、インストール時にアプリケーションが鍵を要求するようにします。一意のトークンと署名を分割し、公開鍵を使用して署名がそのトークンに対して有効であることを確認できます。

このアプローチでは、いくつかの暗号化ライブラリをソフトウェアにバンドルする必要があり、ほとんどのアルゴリズムはセキュリティのために非常に長い署名を使用するため、シリアル番号を入力するのがかなり面倒になります。ユーザーが番号をコピーして貼り付けると予想される場合は問題ありません。

これらの理由から、多くのソフトウェア パッケージは、チェック アルゴリズムが完全にクライアントに組み込まれている、安全性の低いキー検証スキームを使用しています。これはハッシュかもしれません。シリアルの最後の 16 進数の 4 桁は、「秘密」キーと組み合わせた残りのシリアルの SHA1 ハッシュの下位 2 バイトと一致する必要があります。ただし、キーはアプリケーションにバンドルする必要があるため、ハッカーがアプリ コードを見て「秘密」キーを抽出し、独自のキー ジェネレーターを作成できるようにする可能性があります。

そのため、一部のプログラムでは「keygens」が利用可能であることがわかります。このアプリは、クラッカーが鍵作成プロセスを再現できるように、アプリケーションに十分な情報を残した安全性の低いチェック アルゴリズムを使用していました。公開鍵暗号またはインターネット アクティベーションに基づくより安全なセットアップを備えたプログラムの場合、通常、代わりに、チェック コードが変更または削除された「クラックされた」バージョンのアプリケーションが表示されます。

...これは、あなたが何をしても、誠実さを強制することはできないことを示しています. ですから、あまり心配しないでください。

于 2010-09-10T20:57:50.193 に答える
1

ランダムなシリアル番号を一元的に作成したい場合は、数字と文字の配列からランダムに取得するだけで十分です。毎回新しいインデックスを取得するために使用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 ;
}

それらをコードで配布するか、プログラムに有効なシリアル番号をチェックさせるかは、別の問題です。

于 2010-09-10T21:03:10.823 に答える
0

何が必要かは完全にはわかりませんが、一意の識別子を作成するhttp://www.php.net/manual/en/function.uniqid.phpがあります。

それらがどのように作成されるかにもっと興味がある場合は、PHPソースを見て、uniqidがどのように実装されているかを確認することをお勧めします。

于 2010-09-10T20:04:36.733 に答える
0

もう少し情報が必要です。ゲームを購入するときのようにシリアル キーを作成したいですか、それとも一意のユーザー ID のシリアルが必要ですか。

シリアル番号は、有効期限の日時などの情報を保存する必要がありますか?

@nikic - 乱数発生器を開始するためのベースとしてのすべてのランドの使用時間。国防総省が溶岩ランプを使用するのはそのためです。溶岩ランプ専用の部屋全体があり、レーザーを照らしてランダムに一意のキーを作成します。

編集:

有効にする必要があるのは、C# アプリケーションがサイトとの通信に使用する方法です。

C# がシリアル番号が正しいことを確認できるように、php でキーを作成してデータベースに保存する必要があります。

次に、キーが認証されたかどうかを C# アプリケーションが認識できるように、PHP が別の値を返すかどうかを確認する必要があります。

貼り付けで行ったことは、公開鍵と秘密鍵を作成することでした。公開鍵は、製品を検証するためにユーザーに提供されます。製品を検証するか、システムにログインすると、公開鍵がデータベースに対してチェックされ、戻り値が秘密鍵になります。C# プログラムとのすべての対話中に、ユーザーが更新を確認したり、サーバーから情報を取得したりする必要がある場合、サーバーへのクエリに秘密キーが追加され、エンド ユーザーが正当であることを確認します。

私も使用した別の方法は上記ですが、ユーザーがキーを共有していないことを確認するために追加のチェックを追加しました。C# アプリケーションは、コンピューター内のプロセッサのシリアル番号を取得し、アプリケーションの登録時にそれをデータベースに保存します。次に、別の誰かが同じ公開キーを使用してプロセッサのシリアル番号が異なる製品を登録しようとすると、エラーがスローされ、サポートに連絡する必要があります。これを行うと、5 つの異なるマシン ID を許可したり、必要な数だけ許可したりできます。

登録キーの作成は、オフセット (ユーザー名など) を含むランダムな文字列を作成するだけでよいため、非常に簡単です。

ただし、誰かが提供した名前または会社名に基づいて登録キーを作成し、そのアルゴリズムを C# プログラムに追加することもできます。その欠点は、C# ソース コードを簡単に逆コンパイルできることです。実際に製品の代金を支払うことなく、登録コードを簡単に作成するためのアルゴリズムを見つけることができます。認証を行うサーバーを追加することで、誰かが独自のシリアル キーを生成することははるかに困難になります。

于 2010-09-10T20:48:15.330 に答える