在上一篇文章《Silverlight中非對稱式加密及數位簽章RSA演算法的實現》中,我實現了一個Silverlight中可用的RSA演算法。這一篇文章我將實現一個實驗性的Silverlight控制項純用戶端註冊驗證機制。希望做過這方面的朋友多給些指導性意見。
先給大家介紹一下Silverlight用戶端控制項的使用情景。一般來說,Silverlight用戶端控制項會銷售給開發Silverlight程式的公司,他們是控制項的購買者。他們開發的程式中會用到Silverlight用戶端控制項。但是Silverlight控制項最終是在瀏覽Silverlight程式的網站使用者機器上執行的。說的有點繞,請參照。
這個純用戶端註冊驗證機制主要流程如下:
1, 控制項購買者下載使用Silverlight控制項(Silverlight控制項中包含PublicKey及驗證License的邏輯)。
2, 控制項購買者通過控制項產生商提供的網站輸入一些註冊資訊(如輸入程式部署路徑等唯一標示),付費,完成註冊。控制項產生商會記錄這些資訊,並使用PrivateKey產生一個RSA簽名過的License檔案。
3, 控制項生產商會將這個RSA簽名過的License檔案返回給控制項購買者。
4, 控制項購買者會將License檔案綁定到他開發部署的程式中。
5, 網站使用者瀏覽控制項購買者開發部署的網站,下載Silverlight控制項在網站使用者機器上執行,並驗證License檔案的簽名及程式部署路徑等唯一標示。
這個驗證性Demo中的License格式如下:
<License>
<Id>31f81fef-a036-4f6f-b47b-d0c8da1674ea</Id>
<AssemblyName>Vendor.TestControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=696fd0988622108f</AssemblyName>
<AuthorisedApp>http://localhost:8888/ClientBin/Customer.TestApp.xap</AuthorisedApp>
<Signature>MVALuQLzIK8SWfZ5q25/PD3P6ZV0FLqIhCt5YcZ7yNkBTuLABg/TGggC4imU2S6QyZBOLsXyEOSFfXXxBn7Spwhkr6P+CbQb0MvotPgr5nenLdccm7UwABkn7+PgtEchObGba5KUhHCAkvvSFfwi/e480AYI2YXznVpCsP8RA8o=</Signature>
</License>
License中記錄了控制項產生商資料庫中License資訊記錄Id,強式名稱簽名的目標控制項程式集全名,程式部署路徑等一些唯一性標示及防止篡改這些資訊的RSA數位簽章。
當使用者瀏覽網站時,Silverlight控制項會下載到在使用者機器上執行,從而進行註冊碼驗證工作。它會首先驗證License的合法性(即使用RSA簽名驗證演算法檢驗License檔案是否被篡改),然後會判斷程式集及唯一性標示是否正確。從而判斷控制項是否成功註冊。
驗證License合法性代碼如下:
代碼
public class License
{
private static readonly string PublicKeyXmlString = "<RSAKeyValue><Modulus>wG5DRppiesQegis92ZyJOO3ADC6ANV470SPyOhuYBpDpwA/UX4gO3XQhEr2jx09ZLQWYvwVJdSg4JhoO46fw11nsQObzwd+wz/jEcjSF9MCfK+CVb3qMHH9TBgHh5dy7zbB+hUkuacm/nKY9bPfaoNj4sA2YnbiPl3+v80qy/gE=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
private static readonly RSAManaged.RSAPublicKey PublicKey = null;
static License()
{
PublicKey = RSAManaged.RSAPublicKey.FromXmlString(PublicKeyXmlString);
}
internal License()
{
}
internal string Id { get; set; }
public string AssemblyName { get; internal set; }
public string AuthorisedApp { get; internal set; }
internal byte[] Signature { get; set; }
public bool IsValid()
{
//在這裡驗證License是否合法
byte[] signData = Encoding.UTF8.GetBytes(this.Id + this.AssemblyName + this.AuthorisedApp);
SHA1Managed sha1 = new SHA1Managed();
bool verifyResult = RSAManaged.RSAManaged.Verify(signData, PublicKey, sha1, this.Signature);
sha1.Clear();
return verifyResult;
}
驗證程式集全名及程式部署路徑等唯一性標示代碼如下:
代碼
private static bool ValidateLicenseFile()
{
AssemblyName assemblyName = new AssemblyName(Application.Current.GetType().Assembly.FullName);
Uri uri = new Uri("/" + assemblyName.Name + ";component/license.lic", UriKind.Relative);
StreamResourceInfo sri = Application.GetResourceStream(uri);
if (sri == null)
{
return false;
}
string licenseXmlString = new StreamReader(sri.Stream).ReadToEnd();
License license = License.FromXmlString(licenseXmlString);
if (license == null || !license.IsValid())
{
return false;
}
//在這裡驗證程式集全名是否合法
if (Assembly.GetExecutingAssembly().FullName != license.AssemblyName)
{
return false;
}
//在這裡驗證程式部署路徑等唯一性標示
if (Application.Current.Host.Source.AbsoluteUri != license.AuthorisedApp)
{
return false;
}
return true;
}
優缺點分析:
+使用私密金鑰簽名,公開金鑰驗證,能有效防止偽造License檔案及分析代碼寫出註冊機(不考慮篡改程式邏輯的爆破方式)。
+純用戶端驗證不需要跨域訪問,也不需要控制項購買者在程式發行伺服器端部署其他東西。
-比直接輸入註冊碼麻煩
-在現在的Silverlight版本中,只找到部署地址這個特徵標示,因此只能做部署License授權。不能做成像WinForm控制項那樣為每個開發人員機器授權的方式。
以上是我對Silverlight控制項純用戶端註冊驗證機制的初步想法。不知道大家有沒有更好的點子。在Silverlight下能做成像WinForm控制項那樣為每個開發人員機器授權的方式嗎?歡迎大家給些意見。
本文基於署名 2.5 中國大陸許可協議發布,歡迎轉載,演繹或用於商業目的,但是必須保留本文的署名KevinShan(包含連結)。如您有任何疑問或者授權方面的協商,請給我留言。
驗證性Demo原始碼下載:
SilverlightLicense1.zip