web-dev-qa-db-ja.com

C#デスクトップアプリケーションのライセンス

C#デスクトップアプリケーションにライセンスを追加するにはどうすればよいですか?無許可のユーザーがソフトウェアをインストールするのを防ぐための適切な無料の方法を見つける必要があります。

30
Noro

.NET用のライセンス管理システムはたくさんあります(1つでもあります ライセンス管理用の組み込み )。 「.NETライセンスマネージャー」を探し回るGoogleは、無料の Open License システムをリリースしました。

もっと簡単に見つけられると思います。

10
Dr Herbie

おそらく少し遅れていますが、少しのC#アプリケーションをセキュリティで保護するための迅速かつ効果的な方法を試そうとして少し時間を費やし、結果を共有したいと思います。

RSAを使用して、かなり簡単に独自のかなり安全なライセンスシステムを構築できるようです。

明らかに、ソフトウェアを保護することに関して防弾となるものは何もありません(それは強盗から家を保護するようなものです:アラーム、barえる犬、フェンスはそれが価値以上のトラブルを引き起こしますが、誰かが侵入しようとすることを止めません)

したがって、価値のあるものよりもトラブルを起こすことがソフトウェア保護の重要なフレーズです。1,000,000ドルのE.R.Pを提供する場合システムでは、Webサービスを介して承認された本当に優れた保護が必要です(そして、システムに多額を支払うユーザーは、そのシステムに常時インターネットアクセスを許可しても問題はありません)

ただし、小さなアプリに5ドルから30ドルしか請求しない場合、ユーザーは非常に重い手渡しの承認に耐えることはできません。

作成する最も簡単なシステムは、製品、ユーザー、およびその期間の詳細を含むライセンスファイルにデジタル署名することだと思います。

つまり、ライセンスファイルを変更すると、デジタル署名が無効になります。

デジタル署名は、SignDataメソッドを使用して、DSACryptoServiceProviderクラスから取得できます。

データに署名するには秘密鍵が必要であり、その鍵の公開部分は署名の検証に使用できます(したがって、公開鍵はアプリケーションからアクセス可能でなければなりません)

DSAXCryptoServiceProviderには、キーを作成および使用するためのメソッドがあります。

DSACryptoServiceProvider.ToXMLString(bool includePrivate);

現在サービスプロバイダーにある公開キーまたは公開キーと秘密キーをXML文字列として返します。

DSACryptoServiceProvider.FromXMLString(String xmlString)

このメソッドは、DSACryptoServiceProvider.ToXMLString()から取得した既存の秘密鍵または公開鍵で新しいDSACryptoServiceProviderをセットアップします

このシステムのセキュリティ上の唯一の欠陥は、ユーザーが自分の公開鍵を提供することを破る可能性があることです。これにより、ユーザーは独自の秘密キーから独自のライセンスファイルを生成できます。

これは、アプリケーションに必要なリソース(アプリケーションの必須ロジックを含む.dll、または.exe自体など)に追加で署名することで回避できます。したがって、公開キーが変更された場合、この追加の(隠された)署名は無効になります。

これを改善する他の方法には、ライセンス条件を不明瞭にすることが含まれます(バイナリ形式を使用してライセンス条件を含むデータ構造をバイト配列にシリアル化し、Convert.ToBase64String()を使用すると、ライセンス条件が非常に効果的に見えなくなります。データの表現を解決するために必要な公開鍵を置き換えることができました)

私が書いたシステム例はありますが、完全に引用するには大きすぎますが、これはそこからのCreateLicenseメソッドです:

    /// <summary>
    /// use a private key to generate a secure license file. the private key must match the public key accessible to
    /// the system validating the license.
    /// </summary>
    /// <param name="start">applicable start date for the license file.</param>
    /// <param name="end">applicable end date for the license file</param>
    /// <param name="productName">applicable product name</param>
    /// <param name="userName">user-name</param>
    /// <param name="privateKey">the private key (in XML form)</param>
    /// <returns>secure, public license, validated with the public part of the key</returns>
    public static License CreateLicense(DateTime start, DateTime end, String productName, String userName, String privateKey)
    {
        // create the licence terms:
        LicenseTerms terms = new LicenseTerms()
        {
            StartDate = start,
            EndDate = end,
            ProductName = productName,
            UserName = userName
        };

        // create the crypto-service provider:
        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();

        // setup the dsa from the private key:
        dsa.FromXmlString(privateKey);

        // get the byte-array of the licence terms:
        byte[] license = terms.GetLicenseData();

        // get the signature:
        byte[] signature = dsa.SignData(license);

        // now create the license object:
        return new License()
        {
            LicenseTerms = Convert.ToBase64String(license),
            Signature = Convert.ToBase64String(signature)
        };
    }

検証方法:

    /// <summary>
    /// validate license file and return the license terms.
    /// </summary>
    /// <param name="license"></param>
    /// <param name="publicKey"></param>
    /// <returns></returns>
    internal static LicenseTerms GetValidTerms(License license, String publicKey)
    {
        // create the crypto-service provider:
        DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();

        // setup the provider from the public key:
        dsa.FromXmlString(publicKey);

        // get the license terms data:
        byte[] terms = Convert.FromBase64String(license.LicenseTerms);

        // get the signature data:
        byte[] signature = Convert.FromBase64String(license.Signature);

        // verify that the license-terms match the signature data
        if (dsa.VerifyData(terms, signature))
            return LicenseTerms.FromString(license.LicenseTerms);
        else
            throw new SecurityException("Signature Not Verified!");
    }

ライセンス条項クラス:

    /// <summary>
    /// terms of the license agreement: it's not encrypted (but is obscured)
    /// </summary>
    [Serializable]
    internal class LicenseTerms
    {
        /// <summary>
        /// start date of the license agreement.
        /// </summary>
        public DateTime StartDate { get; set; }

        /// <summary>
        /// registered user name for the license agreement.
        /// </summary>
        public String UserName { get; set; }

        /// <summary>
        /// the Assembly name of the product that is licensed.
        /// </summary>
        public String ProductName { get; set; }

        /// <summary>
        /// the last date on which the software can be used on this license.
        /// </summary>
        public DateTime EndDate { get; set; }

        /// <summary>
        /// returns the license terms as an obscure (not human readable) string.
        /// </summary>
        /// <returns></returns>
        public String GetLicenseString()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-Steam;
                bnfmt.Serialize(ms, this);

                // return a base64 string representation of the binary data:
                return Convert.ToBase64String(ms.GetBuffer());

            }
        }

        /// <summary>
        /// returns a binary representation of the license terms.
        /// </summary>
        /// <returns></returns>
        public byte[] GetLicenseData()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-Steam;
                bnfmt.Serialize(ms, this);

                // return a base64 string representation of the binary data:
                return ms.GetBuffer();

            }
        }

        /// <summary>
        /// create a new license-terms object from a string-representation of the binary
        /// serialization of the licence-terms.
        /// </summary>
        /// <param name="licenseTerms"></param>
        /// <returns></returns>
        internal static LicenseTerms FromString(String licenseTerms)
        {

            using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(licenseTerms)))
            {
                // create a binary formatter:
                BinaryFormatter bnfmt = new BinaryFormatter();

                // serialize the data to the memory-Steam;
                object value = bnfmt.Deserialize(ms);

                if (value is LicenseTerms)
                    return (LicenseTerms)value;
                else
                    throw new ApplicationException("Invalid Type!");

            }
        }

    }
58
Simon Bridge

技術的には、実用的で安全なライセンスシステムを作成するのは容易ではありません。商用ソフトウェアの開発を計画している場合、商用ソフトウェアを使用することをお勧めします。カスタムコード化されたライセンスシステムは脆弱である傾向があります。

Treek's Licensing Library で最高の経験があります。単一の開発者にとっても安価であり、安全で優れたサポートがあります。コストを比較するとき、TLLは同じ仕事をするためにあなた自身の開発者を借りるよりも安いです。

また、ソースを保護する必要があります。そのために EAZ Fuscator を使用しますが、無料のオプションも利用できます。 EAZは非常に優れていますが、非常に高価です。

2
panpernicek

1つのアプローチは、独自の 部分キー検証システム を展開することです。 Code Projectで利用可能なVB.NETバージョンがあります。

http://www.codeproject.com/KB/security/cdkeys.aspx

0
CtrlDot

アプリの保護にどれだけの労力を注いでいるかに注意してください。簡単に壊れたり、非常に強力な場合(たとえば、実行するたびにパスワードを入力する必要がある場合)にユーザーに公開するのをやめると、無駄な時間がかかる場合があります。

(ゲームの)ソフトウェア保護に関する興味深い記事は、ここにあります: http://www.positech.co.uk/talkingtopirates.html

0
Tony