前言:这段时间做的项目涉及到WebService的安全领域,了解到了WSE,但在CSDN里基本搜不到任何资料,Baidu出来的中文资料也是少之又少,折腾了一周,走了不少弯路,在此将自己的经验与大家分享, 希望对入门者有所帮助,能力有限,文中不足之处还请指正。
WSE全称Web Services Enhancements,它是由微软开发的实现了WS-Security标准的增强插件,目前最新版本为WSE 3.0,下载地址:http://download.microsoft.com/download/5/5/1/5511bfc6-e52f-4db0-bafb-fd5dcb91eff0/Microsoft%20WSE%203.0.msi。
与WSE密切相关的还有“数字证书”,通过它实现了数据的加密传输与通信双方的真实性验证,数字证书的原理大至是这样:比如我要登录一家银行网站进行在线支付,我怎么确认这个网站就是该银行的站点呢?如果有人仿冒骗取了我的账号密码怎么办?这时CA(证书服务)以可信的第三方出现,当我访问该银行站点时,银行站点向我出据它的证明:这是我的签名,请你去CA验证真伪,于是我会在得到CA肯定之后才会在此银行站点进行我的支付操作。
所以按我的理解,WSE证书应用在Server端(提供Web Service)应该拥有一个包含公钥与私钥的证书,该证书由CA颁发,而Client端(调用Web Service)的证书附本只拥有公钥,当Client向Server发送请求时,Server用它的私钥签名,Client拿着签名去CA验证,通过验证后双方约定加密方式,然后开始数据传输。我不知道我的理解是否正确,还请大家指正。
OK,如果按照上面的思维,在配置WSE时逻辑就很清晰了,一是Server端的证书配置,二是Client端的证书配置。
测试环境:Windows Server 2003 SP2,Visual Studio 2005,.Net Framework 2.0
一、WSE 3.0的安装
选择开发环境的跟Visual Studio 2005整合方式安装。
以下假设A为Server,B为Client。
二、Server端的证书配置
首先第一步应该从CA上获取一个包含私钥的服务端证书,但绝大多数的证书服务是收费的,之前我也花了几天时间尝试在Windows 2003下安装一个自己能免费使用的CA,但安装成功后能申请的只有服务器身份验证、邮件验证、WEB客户端验证等为数不多的几项证书,它们均不能在WSE下正常使用,这个问题等以后时间充裕解决了再与大家分享。现在我们使用微软提供的证书创建工具Makecert.exe与证书管理工具Certmgr.exe来生成证书,这两个工具的介绍参见http://msdn2.microsoft.com/zh-cn/library/bfsktky3(VS.80).aspx 与 http://msdn2.microsoft.com/zh-cn/library/e78byta0(VS.80).aspx。
Visual Studio的安装目录下其实已包含这两个工具的,现在我们在C盘下新建文件夹C:/Cert,把Makecert.exe、Certmgr.exe以及Wse3.0安装目录下的winhttpcertcfg.exe三个文件拷贝到该文件夹,然后创建一Go.bat内容如下:
set CERTNAME=TestServiceCert
certmgr -del -r LocalMachine -s My -c -n %CERTNAME%
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN=%CERTNAME% -sky exchange -pe
set WP_ACCOUNT=NETWORK SERVICE
(ver | findstr "5.1") && set WP_ACCOUNT=%COMPUTERNAME%/ASPNET
winhttpcertcfg -g -c LOCAL_MACHINE/My -s %CERTNAME% -a "%WP_ACCOUNT%"
iisreset
pause
在命令模式下执行C:/Cert/Go.bat
这个批处理文件执行的操作就是在服务器上创建一个包含公钥和私钥的证书,然后将证书安装在指定账号能访问的位置,最后设定证书的私钥能被ASPNET访问,TestServiceCert为证书名字。
三、Client端证书配置
上面在机器A上生成了服务端证书,这里我们将使用该服务端证书生成客户端证书,并在客户端机器B上完成客户端证书的布署,注意客户端证书是不包含私钥的:
1、在机器A上:开始菜单-->运行-->mmc-->文件-->添加/删除管理单元--->添加-->证书-->计算机账户-->下一步-->完成-->关闭-->确定
2、找到“个人”下的“证书”节点,这时在右边窗口我们就能看到TestServiceCert这个证书了,右击-->所有任务-->导出-->下一步-->选择“不要导出私钥”-->选择Der或Base64编码-->将文件导出至C:/Cert/Client.cer
3、先将Client.cer拷贝到机器B上,然后在机器B上点击开始菜单-->运行-->mmc-->文件-->添加/删除管理单元--->添加-->证书-->计算机账户-->下一步-->完成-->关闭-->确定
右击“其它人”节点-->所有任务-->导入-->选择“Client.cer”文件并导入。
四、编写UsernameTokenManager
UsernameTokenManager用于辅助完成服务器端对客户端提交过来的用户名密码进行验证功能。客户端用用户名、密码等信息创建UsernameToken对象,WSE通过Soap Header将相关信息传递给Web Service,Web Service接收到请求后,WSE可以从Soap Header中得到UsernameToken的相关信息并构造这个对象。我们在这一个步骤中编写的UsernameTokenManager,就是在Web Service端根据用户名去获取用户密码,并将密码返回给WSE 3.0,WSE 3.0将验证这个密码与客户端提交的密码是否一致,来完成对客户端的认证。
新建一“类库”工程:Model,添加对Microsoft.Web.Services3.dll的引用,然后在Model下新建类MyUsernameTokenManager.cs,代码如下:
using System.Xml;
using System.Security.Permissions;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.Tokens;
namespace Model
{
/// <summary>
/// MyUsernameTokenManager 的摘要说明
/// </summary>
public class MyUsernameTokenManager : UsernameTokenManager
{
public MyUsernameTokenManager() { }
public MyUsernameTokenManager(XmlNodeList nodes) : base (nodes) { }
protected override string AuthenticateToken(UsernameToken token)
{
// token在客户端保存了Password,只将Username传送到Webservice
// 然后Client比较这个返回的Password与之前保存的Password是否一至
return "abc";
}
}
}
五、WSE3.0的服务端配置
新建一Web站点项目,添加对Microsoft.Web.Services3.dll的引用,添加Web.Config文件。右击项目,选择WSE Settings 3.0。
1、勾选上General标签下的Enable this project for Web Services Enhancements和Enable Microsoft Web Services Enhancement Soap Protocol Factory。
2、在Security标签下添加一个Security Tokens Managers,先在Built In Token Managers中选择User Name Token Manager,然后把Type替换成Model.MyUsernameTokenManager, Model。
3、在Policy标签中选择Enable Policy,添加一个Policy命名为ServerPolicy,确定后进入WSE Security Settings Wizard。选择Secure a service application,Client Authentication Method选择Username。接下来的对话框中Perform Authorization不要勾选。随后的屏幕如下:
4、添加Test.asmx,在Test.cs代码中添加using Microsoft.Web.Services3;。为Web Service的类添加Attribute以应用上面定义的安全策略。
六、WSE3.0客户端配置
添加一“网站”项目,添加“Web.Config”文件,右击项目,选择WSE Settings 3.0。
1、勾选上General标签下的Enable this project for Web Services Enhancements
2、在Policy标签下选择Enable Policy,添加一个Policy命名为ClientPolicy,确定后进入WSE Security Settings Wizard。选择Secure a client application,Client Authentication Method选择Username。勾选Specify Username Token in code。接下来Message Protection的选择跟前面Web Service端的贴图完全一样。然后是选择证书,Store选择LocalMathine,因为前面已经机器B上导入了Client.cer证书,所以点击Select Certificate按钮后可以看到TestServiceCert的证书,导入。
打开wse3policyCache.config文件修改红色部分如下:
<x509 storeLocation="LocalMachine" storeName="My" findValue="CN=TestServiceCert" findType="FindBySubjectDistinguishedName" />
3、添加Web Service引用。引用地址http://机器A IP/WSEServer/Test.asmx,不能用localhost。Web Reference Name取名TestRef,添加Default.aspx,其CS代码如下:
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3.Security;
using Microsoft.Web.Services3.Security.X509;
using Microsoft.Web.Services3.Security.Tokens;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
try
{
TestRef.Test1Wse myRef = new TestRef.Test1Wse();
myRef.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Default;
// user name token
string userName = "abc";
string password = "abc";
UsernameToken token = new UsernameToken(userName, password);
myRef.SetClientCredential(token);
// apply policy
myRef.SetPolicy( " ClientPolicy " );
// call web service
Response.Write( " Calling " + myRef.Url);
string result = myRef.HelloWorld();
Response.Write( " Result : " + result);
}
catch (Exception error)
{
throw error;
}
}
}
七、完成
在IE中打开Default.aspx,就能看到输出的结果。