欢迎光临
我们一直在努力

用WSE在Web服务中验证用户身份-ASP教程,客户端相关

建站超值云服务器,限时71元/月

一、web服务安全与ws-security

  毫无疑问,soap和xml web服务在交互操作和标准上已经完全改变了电子商务领域的格局。

  然而直到最近,在web服务技术领域仍然存在着一些缺陷,那就是处理消息级别的安全、认证、加密、数字签名、路由和附件等问题的能力。为了解决这些安全问题,像ibm、microsoft和verisign这样的公司和组织正牵头合作制定统一的web服务安全规范,以便利用它们原有的web服务交互操作概念和商业模型,他们推出了ws-security等规范。可以这么说,自从soap规范形成以后,ws-security规范及其后续的工作可能是web服务技术领域的一次最重要的进步。

  随着ws-security规范的定稿,各大软件厂商开始认真地考虑为其产品提供使用相同web服务安全语言的接口和编程工具箱,web服务开发者也将能够使用这些厂商提供的工具加强他们所开发的web服务的安全性。

  二、wse安全性能简介

  microsoft推出了web services enhancements 1.0 for .net(以下简称wse),它是一个类库,用于实现高级 web 服务协议,这也是该公司的第一个使用ws-security等规范实现soap消息安全的工具套件。

  保护web服务安全的一个很重要的环节就是保护其soap消息传递的安全。

  使用wse后,soap消息可以自己验证其完整性,并可使用定义在ws-security规范中的机制加密。

  wse1.0支持的所有ws-security特性都是通过实现securityinputfilter和 securityoutputfilter对象的安全性输入输出过滤器实现的,它支持的安全特性有:

  1. 数字签名

  2. 加密

  3. 使用用户名令牌签名并加密

  4. 使用x.509证书签名并加密

  5. 使用自定义二进制令牌签名并加密

  wse1.0不支持security assertion markup language(saml,安全声明标注语言),但microsoft公司正积极在其.net server中实现saml体系结构。当然,开发者自己可以自由的实现saml。唯一的不足是还不能使用wsdl描述遵循ws-security规范的web服务的ws-security接口。

  wse的体系结构模型基于处理入站和出站soap消息的过滤器管道。它是建立在已有的soapextension类的基础上的,有使用过soapextension类行进压缩、加密、记录和其它操作经验的开发者会发现他们对wse其实很熟悉。

  wse提供了一个microsoft.web.services.soapcontext类,让我们可以处理ws-security soap头和其它入站的soap消息头,同时可为出站的soap消息添加ws-security头。wse还有一个包装类为soap请求和响应添加soapcontext(与httpcontext类似),同时服务器使用一个soapextension类“microsoft.web.services.webservicesextension”,让我们可以验证入站的soap消息,还提供了我们可从我们的webmethod中访问的请求和响应soapcontext。

  学习使用wse最大的障碍在于有时很难理解microsoft的技术文档和相关文章,即使对于那些有丰富经验的高级开发人员来说也是如此,并且关于这方面的文章很少。在本文中,我将给出一个简单的例子,介绍如何使用wse实现基本的用户名令牌的验证过程,以保证web服务的安全。

  三、设置wse环境

  为了设置基本的wse环境,我们需要配置asp.net应用程序,使其能够使用wse soapextension。最简单的方法是把所需的/configuration/system.web/webservices/soapextensiontypes/add元素添加到你的web服务虚拟目录中的web.config里,如下所示:

<webservices>
<soapextensiontypes>
<add type=”microsoft.web.services.webservicesextension, microsoft.web.services, version=1.0.0.0, culture=neutral, publickeytoken=31bf3856ad364e35″ priority=”1″ group=”0″ />
</soapextensiontypes>
</webservices>

  注意type属性必须写在一行中,但是在文中考虑到篇幅的问题需要把它分为几行,所以请读者多加注意。而且要注意,在开始使用wse之前,我们必须在工程中加入对microsoft.web.services.dll的引用。
  四、基本的用户名令牌认证

  在我们数字签名soap消息之前,必须先弄清楚谁正在签名。因此,我们将探讨一下用户名令牌(usernametoken)的概念,同时了解wse如何允许我们验证用户名令牌。

  为了在web服务中使用wse验证用户名/密码,我们需要知道wse在这方面为我们提供了什么?ws-security定义了一个usernametoken元素,它提供了基本用户名/密码验证的方法。如果你有使用http的经验,那么你会发现usernametoken与basic authentication非常类似。有三种用户名令牌,但是通常情况下我们只对最后两种最感兴趣:

<!–明文密码–>
<usernametoken>
<username>user1</username>
<password type=”wsse:passwordtext”>suangywang</password>
</usernametoken>

  这种方法使用明文密码。我们不难想象,在服务器上将进行核对数据库,验证用户名与密码,看是否有匹配的用户名/密码对这一系列验证操作。

<!–密码摘要–>
<usernametoken>
<username>user1</username>
<password type=”wsse:passworddigest”>
qsmako67+vzynu9tcmsqofxy14u=
</password>
</usernametoken>

  这种方法发送一个密码摘要(digest)代替明文密码。使用密码摘要,密码就不会通过网络发送,这样黑客就不太可能算出web服务的密码。密码摘要是用散列函数计算的。这个过程只是单向的,意味着将函数反向并找到对应于摘要的消息是不可能的,因为该过程以这样一种方式实现,所以找到散列到同一摘要的两条不同密码在计算上难以实现。但是黑客可以发送散列密码,然后冒充原始发送人被验证。为了避免这个问题,web services security addendum(web服务安全补遗)已经增加一个辅助的保护措施。补遗中规定必须发送密码的摘要版本,而不仅仅发送散列密码。这个摘要信息包含一个密码散列,标识请求的唯一的nonce和创建时间。因此绝对不会出现相同的两个密码散列。如下所示是修正后的用户名令牌usernametoken。

<!–修正后的用户名令牌–>
<wsse:usernametoken
xmlns:wsu=”http://schemas.xmlsoap.org/ws/2002/07/utility”
wsu:id=”securitytoken-59845323-5dcb-4a6b-a7fb-94a0d7357a20″>
<wsse:username>user1</wsse:username>
<wsse:password type=”wsse:passworddigest”>
gpbdxjx79eutcxdtlulilcrsirs=
</wsse:password>
<wsse:nonce>
h52si9pkv0bvrpuolqc7cg==
</wsse:nonce>
<wsu:created>2003-6-20t21:16:50z</wsu:created>
</wsse:usernametoken>

  虽然每个合法请求都有一个不同的散列,但是你也必须防止恶意用户把其他用户的合法请求中的整个usernametoken拿出放入自己的非法请求中。你可以使用timestamp(时间戳标头)来最小化这种危险。时间戳标头用来表示消息的创建时间和过期时间,指明消息的周期以及何时可以认为该消息失效。 例如,你可能想指定消息在40秒以后失效,并且超过40秒服务器就不会接收usernametoken。但是机器之间的时钟同步问题可能会造成有效的请求被拒绝的情况。所以使用时间戳也并不是一个尽善尽美的解决方法。为了解决这个问题,web服务可以保存一张最近收到的usernametoken的nonce值的表,如果收到的一个请求的nonce值已经被使用了,那么就绝对不会接受这个请求。如果你接收几个使用相同nonce的请求,那么你要考虑把这几条请求全部丢弃,因为很有可能先到的请求是非法请求。还要了解到nonce核对技术并不能防止恶意用户截获合法的输入信息,并把原始信息中的usernametoken加入自己的消息,然后发送到目的地。这时就需要为消息添加数字签名或安全证书,以保护其不受攻击。数字签名和安全证书的相关知识在本文中不会涉及,请读者查阅相应文献。

  所有的散列保护都需要消息发送端和接收端知道用户的密码。在客户端,人们期望系统能够提示用户输入密码。而在服务器端,需要保存带有有效用户名/密码对的表,以供系统查找。我们下面将介绍wse如何使用一个password provider(密码提供者)机制来解决这两个问题。

  五、ipasswordprovider接口

  wse定义了一个microsoft.web.services.security.ipasswordprovider接口类,我们必须实现这个类来注册一个密码提供者。这个接口有一个方法getpassword,它接收一个microsoft.web.services.security.usernametoken作为输入参数,该方法返回指定用户的密码。其思想是你可以使用任何你想用的机制保存有效的用户名/密码对,然后提供了一个实现ipasswordprovider接口的类,来让wse访问你的特定密码存储机制。你甚至可以执行你自己的usernametoken的摘要(digest)和散列(hash)的组合,甚至使用一个共享的密码,以进一步控制你的认证基础结构。

  为了把你特定的password provider(密码提供者)告诉wse,你必须配置合适的wse设置。首先要添加一个microsoft.web.services元素到应用程序的配置文件中的配置元素中。还要指定可以读懂特定配置信息的wse类。可以把下面的configsections添加到机器上的machine.config或单独的web.config中。

<configsections>
<section name=”microsoft.web.services”
type=”microsoft.web.services.configuration.webservicesconfiguration,
microsoft.web.services, version=1.0.0.0, culture=neutral,
publickeytoken=31bf3856ad364e35″ />
</configsections>

  在本例中,我们将使用northwind数据库employees表的一个修改版本来进行查询任务。因为passwordprovider接口需要返回一个与usernametoken对象的密码部分匹配的实际密码,所以通常,我们只需要使用wse加密我们的用户名和密码,然后再通过网络传送给web服务。

  如果你在solution explorer中选中你的工程并在其上点击右键,你将看到在底部增加了一个新的菜单“wse settings”,你可以在其中设置所有重要的配置和其它使用wse的配置:

  这可让我们很容易的设置password provider implementation(密码提供者实现)元素,decryption key provider implementation(解密钥提供者)元素,x.509 certificate(x.509 证书)设置,甚至是我们希望使用的binary security tokens(二进制安全令牌)。此外,其他的选项卡还可以配置用于wse管道的输入输出过滤器,配置路由,启动诊断功能等等。虽然它不能做我们想做的每件事,但这是wse易用化的一个良好的开端。

  passwordprovider安全元素是web.config中的<configuration>父元素的一个子元素,它告诉wse你使用哪个类来实现passwordprovider接口:

<microsoft.web.services>
 <security>
  <!– namespace . classname , assemblyname –>
  <passwordprovider type=”wsesecurity.wsepasswordprovider, wsesecurity” />
 </security>
</microsoft.web.services>

  让我们看看在本例中如何实现它:

namespace wsesecurity
{
 public class wsepasswordprovider : ipasswordprovider
 {
  public string getpassword(usernametoken token)
  {
   try
   {
    sqlconnection cn = new sqlconnection(system.configuration.configurationsettings.appsettings[“sqlconn”].tostring());
    cn.open();
    sqlcommand cmd = new sqlcommand(“select username, password from employees where username =” + token.username + “”,cn);
    sqldatareader dr = cmd.executereader(commandbehavior.closeconnection);
    dr.read();
    return dr[“password”].tostring();
   }
   catch(exception ex)
   {
    throw new exception (ex.message);
   }
  }
 }
}

  上面我们给出的代码可以完全实现ipasswordprovider接口,通过用户名/密码来验证一个用户,当然了,还可以把它做得更复杂一些,这请读者们自己去完成。实际上,我们在编程的过程中基本没有写太多用户验证的代码,大部分工作都由wse暗中处理了。
  六、编写一个使用ws-security的webmethod

  现在我们需要创建一个使用ws-security的webmethod。 这里,我实现了一个简单的方法,它运行northwind数据库的custorderhist存储过程,接收一个字串userid作为唯一的参数,并返回一个dataset。如果调用web服务的客户端可以通过消息级usernametoken验证,那么就可以取回dataset。如果不能通过验证的话,客户端将得到一个异常,告知它不能通过验证。wse的优点在于你只要付出一点点劳动就可以了,大部分的工作已经由wse在暗中为你完成了,所以你可以把大部分时间花费在构建web服务的内容上,而不是为了构建一个安全的web服务机制而疲于奔命。

[webmethod]
public dataset custorderhist(string custid)
{
 // 只接受 soap格式的请求
 soapcontext requestcontext = httpsoapcontext.requestcontext;
 if(requestcontext==null)
 {
  throw new applicationexception(“non-soap request!”);
 }
 bool valid=false;
 try
 {
  foreach(securitytoken tkn in requestcontext.security.tokens)
  {
   if(tkn is usernametoken)
   valid=true;
  }
 }
 catch(exception ex)
 {
  throw new exception( ex.message + “: ” + ex.innerexception.message);
 }
 if (valid==false)
  throw new applicationexception(“invalid or missing security token.”);
 sqlconnection cn;
 sqldataadapter da;
 dataset ds;
 cn = new sqlconnection(system.configuration.configurationsettings.appsettings[“sqlconn”].tostring());
 cn.open();
 da = new sqldataadapter(“custorderhist ” +custid + “”, cn);
 ds = new dataset();
 da.fill(ds, “custorderhist”);
 return ds;
}

  使用上面的webmethod,我们就可在服务器上实现验证用户名/密码的操作。webmethod必须引用microsoft.web.services和microsoft.web.services.security域名空间。现在,我们要构建一个asp.net客户端,这个客户端能够发送验证所需的soap头,并可调用我们的web服务方法。

  七、构建wse asp.net客户端

  对于客户端,wse提供了继承于system.web.services.protocols.soaphttpclientprotocol类的microsoft.web.services.webservicesclientprotocol类。当你在visual studio.net中选择“add web reference”选项的时候,或者使用wsdl.exe程序创建基于wsdl的客户端代码时,你需要使用soaphttpclientprotocol类。你可做的就是使用visual studio.net中的“add web reference”选项或者wsdl.exe程序为你的客户端生成代理类,然后把代理类从继承于soaphttpclientprotocol改为继承于webservicesclientprotocol。这样代理类就有了requestsoapcontext和responsesoapcontext属性,你可以使用它们访问你发送或接收的ws-security头。在c#工程中,如果你已经使用了“add web reference”选项,你可以点击solution explorer中的“show all files”按钮,点击这个按钮就可在solution explorer的web references结点中显示reference.cs文件,让你可以编辑这个文件。

  为了创建正确的usernametoken和在消息级调用web服务的代理方法,需要使用下面的代码:

private void button1_click(object sender, system.eventargs e)
{
 localhost.securityservicewse wse=new localhost.securityservicewse();
 usernametoken tkn = new usernametoken(txtusername.text,txtpassword.text,passwordoption.sendhashed);
 wse.requestsoapcontext.security.tokens.add (tkn);
 try
 {
  dataset ds=wse.custorderhist(txtcustid.text);
  datagrid1.datasource=ds;
  datagrid1.databind();
 }
 catch(exception ex)
 {
  datagrid1.visible=false;
  lblmessages.text=ex.message;
 }
}

  我们要做的就是从客户端的两个文本输入框txtusername和txtpassword中取得输入字串,然后使用passwordoption.sendhashed把它们结合起来创建一个有效的usernametoken。当调用web服务时,wse soap扩展验证请求的一般格式,然后核对密码散列并从我们的passwordprovider方法中取得的密码。如果两者匹配,我们就可调用web服务方法,客户端返回数据集,显示在一个网格中。

  我们现在已经创建了一个完整的使用wse配合数据库验证sha1摘要散列用户名/密码的web服务,希望读者们能通过本文了解到使用wse保证web服务安全的基本措施和方法,并能在实际工作中合理的去应用。

  在文章的最后,我们给出修改northwind数据库employees表的sql脚本,给这个表添加了所需的username和password列,同时在这个表中插入了一条新纪录,其firstname、lastname、username、password和roles字段分别为“user”,“one”,“user1”,“pass1”和“user”。

use northwind
go
alter table [dbo].
add [username] [varchar] (100) collate sql_latin1_general_cp1_ci_as null ,
[password] [varchar] (100) collate sql_latin1_general_cp1_ci_as null ,
[roles] [varchar] (250) collate sql_latin1_general_cp1_ci_as null
go
insert into employees (firstname, lastname,username, [password], roles)
values(user,one, user1, pass1, user)
go

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » 用WSE在Web服务中验证用户身份-ASP教程,客户端相关
分享到: 更多 (0)