伴隨著.net開發(fā)技術(shù)的成熟,軟件開發(fā)進入控件化時代。越來越多的公司投入軟件開發(fā)領域,企圖控制軟件產(chǎn)業(yè)鏈的上游:提供解決方案。其中一部分公司就是提供控件?丶䦟ν饩拖笫且粋黑盒子,借助于方法,屬性和事件,開發(fā)人員即可輕易的開發(fā)出專業(yè)的應用程序,與此同時,軟件的保護方法也不斷出現(xiàn)。在共享軟件時代,軟件開發(fā)人員開發(fā)好程序,然后設計一個序列號生成算法,對正式許可的用戶發(fā)布序列號,生成注冊文件。在應用程序啟動時檢查注冊文件,如果有則繼續(xù)運行,否則中止運行或是提供部分功能。
.net 技術(shù)的出現(xiàn),也提供了相應的軟件保護解決方案。本文詳細討論.net 技術(shù)的軟件保護方案與實現(xiàn)。我們可以采用各種方式來生產(chǎn)許可,授權(quán)用戶使用我們開發(fā)的控件。常見的方式如下:
- 注冊表。在控件安裝時,在注冊表中寫入相應的鍵值,在控件運行時,查找該鍵,如找不到則拋出異常;
- 許可文件。在控件運行時,查找許可文件,如找不到,則拋出異常;
- 遠程Web服務驗證。在控件運行時,連接到遠程的許可驗證服務器,如能找到值,則表示已經(jīng)授權(quán);
注冊表的驗證方式實現(xiàn)起來容易,但是也很容易發(fā)生驗證異常。如果用戶裝有注冊表監(jiān)控程序,跟蹤對注冊表的每一項改動,則會很容易定位到鍵值,進而分析和利用,此外,這種方式對XCOPY也有影響,不方便部署應用程序;許可文件根據(jù)用戶的硬件信息,比如硬盤序列號,或是MAC地址,郵件,生成一個許可文件,放在控件可以找到的地方,在運行時找到該許可文件,如果找不到,則阻止控件的運行;遠程Web服務需用客戶端能聯(lián)網(wǎng),在控件運行時向服務器發(fā)出查詢許可的命令,如果找不到,則停止運行;如果用戶不聯(lián)網(wǎng),這種方式有局限性,用戶根本不能在脫機的情況下嘗試運行該控件。
需要理解的對象:LicenseProvider
MSDN中的解釋是:提供 abstract 基類以便實現(xiàn)許可證提供程序。從 LicenseProvider 繼承時,必須重寫 GetLicense 方法。我們可以理解為一個許可證的提供程序,在控件需要驗證時,提供許可授權(quán),如果不提供許可,則不能使用該控件,拋出異常。這是個抽象類,不允許實例化,我們從該類派生,并且重寫GetLicense方法。
public class FileLicenseProvider : System.ComponentModel.LicenseProvider { public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) { if (context.UsageMode == LicenseUsageMode.Designtime) { // 開發(fā)人員設計時不需要許可,直接頒發(fā)許可證 return new FileLicense(this, "The App"); } else { string licenseFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, type.FullName+".lic"); if (File.Exists(licenseFile)) return new FileLicense(this, "The App"); else return null; } } } |
通過覆蓋GetLicense方法,我們獲取需要驗證的控件的類型信息,然后在當前應用程序目錄下查找以控件的lic文件,如找到,頒發(fā)許可,否則返回null值。
License
MSDN中的解釋為:為所有許可證提供 abstract 基類。向控件的特定實例授予許可證。通俗的理解就是許可,給控件頒發(fā)的許可,表示控件已經(jīng)授權(quán)過了,可以被使用。下面的代碼可以幫助您理解許可的含義。
public class FileLicense : System.ComponentModel.License { //許可驗證提供程序 private FileLicenseProvider owner; private string key; public FileLicense(FileLicenseProvider owner, string key) { this.owner = owner; this.key = key; } //許可Key,通俗的理解是序列號。 public override string LicenseKey { get { return key; } } public override void Dispose() { } } |
FileLicense會應用到控件上,如果返回給控件的FileLicense為空,則控件會拋出異常。
應用許可提供程序
開發(fā)一個控件,如何應用許可驗證呢?
如下代碼所示,我們開發(fā)一個MyControl的控件,同時給它加上LicenseProvider特性(attribute),這樣在該控件運行時,會用FileLicenseProvider來實行許可驗證。
[LicenseProvider(typeof(FileLicenseProvider))] public class MyControl : WebControl |
此外,我們還需要在控件的構(gòu)造方法中進一步調(diào)用驗證方式:
public MyControl() { try { license = LicenseManager.Validate(typeof(MyControl), this); } catch { HttpContext.Current.Response.Write("MyControl控件未授權(quán),請聯(lián)系程序開發(fā)商"); } } |
如果該控件獲取正確的授權(quán),則會繼續(xù)運行,否則因得不到許可而不能繼續(xù)生成。 LicenseManager類會找到FileLicenseProvider類的GetLicense方法,來獲取許可,經(jīng)過各種驗證方式(注冊表,許可文件)來提供許可實例,如果驗證失敗,則會拋出LicenseException,表示無法找到許可。
許可驗證服務器
在注冊表驗證方式中,我們需要在控件的安裝程序中嵌入腳本,在注冊表中寫入相應的鍵值;在本地許可文件驗證方式下,我們需要根據(jù)序列號生產(chǎn)相應的許可文件;在遠程Web服務的驗證方式下,我們還需要設計一個遠程的驗證服務器,接受客戶端的驗證請求。 下面我們來討論一下如何設計這個服務器應用程序。
Web服務是跨平臺的通用協(xié)議,借助于SOAP(簡單對象訪問協(xié)議),我們能接受各種平臺的驗證請求。
借助于ASP.NET Web服務,我們可以輕易的實現(xiàn)這個服務器端應用。 打開Visual Studio 2008,新建ASP.NET Web Service Application
圖一 新建Web Service
把新建的服務名稱改LicenseService.asmx,然后在該服務中提供驗證方法
[WebMethod] public bool ValidateLicense(string mac) { bool ret = Validate(mac); return ret; } |
Validate方法會去查找數(shù)據(jù)庫記錄,返回結(jié)果,提供給客戶端。 為此,我們還需要設計數(shù)據(jù)庫。
圖二 SQL設計視圖
這里,我們采用驗證客戶端MAC地址的方式,如果能找到該地址,則把Enabled設為1,否則找不到,表示該MAC地址未授權(quán),返回false給許可驗證提供程序。SQL 腳本如下:
CREATE TABLE [dbo].[LicenseUser]( [MAC] [varchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL, [Enabled] [smallint] NULL, CONSTRAINT [PK_LicenseUser] PRIMARY KEY CLUSTERED ( [MAC] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] |
應用程序
由于開發(fā)的是Web控件,我們設計一個Web站點,來測試我們的控件保護方案。右擊解決方案,添加現(xiàn)有站點(Web site)
圖三 添加現(xiàn)有站點
把我們的控件從工具欄中拖動到一個Web頁面中,生成應用程序,然后F5,調(diào)試運行。頁面的源代碼如下:
<uc:MyControl ID="MyControl1" runat="server" />
另外,在Web.config中添加如下代碼,您可以不必在每一個頁面中都加入控件引用。
<pages> <controls> <add tagPrefix="uc" namespace="HTSystem" assembly="HTSystem.Component, Version=1.1.0.0, Culture=neutral, PublicKeyToken=c2c8c99b69b1086e"/> </controls> </pages> |
您可能也注意到了,我們給自己寫的組件MyControl添加了版本和強命名元數(shù)據(jù),這樣可以保護我們的組件。
總結(jié)
本文試圖給您提供幾種常用的許可驗證的方式。文中詳細討論了許可文件的驗證方案,分析了如何借助Web服務技術(shù),設計遠程驗證服務器,另外,您還應該了解注冊表的方式的驗證方式。 您可以通過閱讀源代碼,詳細了解這三種方式的實現(xiàn)。