在上一篇文章《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控件那样为每个开发人员机器授权的方式吗?欢迎大家给些意见。
验证性Demo源代码下载:
SilverlightLicense1.zip