2003-01-08 09:33
在.NET中建立Web service安全措施(第一部分)
到目前为止安全性是开发和部署Web service的最基本的内容之一。有很多的论文、文档以及示例说明怎样保护Web service,但是这些信息中的绝大多数所涉及到的都是些有关理论和实践的高级、抽象的定义,很少人提及其具体实现。
在这个三部系列的第一部分,我们将通过一个使用定制的SOAP HEADER的例子来讨论一些有关具体编程的Web service安全性。示例Web service将使用cookie去获取用户的安全环境(context),从而在方法间维护状态,Web service消费者将使用一个Windows应用程序来实现。
一个可重用安全模式
典型的Web
service一般是作为一个ASP.NET应用的附加功能或者API而存在的。Web
service既可以直接地与数据库交互,也可以在一个N层解决方案中通过调用中间件来完成其功能。在应用程序中Web
service需要知道是谁调用了它以及那个用户具有什么样的特权。
多数情况下,用户、角色、商业规则以及授权是已经实现了的,你只要简单地提取这些信息。Web service需要实现一个模式以确定请求客户的信任凭证。理论上在Web service中可以传递用户ID和密码给每个方法,但是一个更面向对象的方法是创建一个继承System.Web.Services.Protocols.SoapHeader的类。这个类将成为我们的SOAP Header,它将被传递到Web service,其中包含我们用来验证用户的所有信息。
服务器实现
下面的列表1给出了一个简单Web
service的服务器端实现代码,SecureWebServiceTester.asmx,以及相关的SOAP Header类:
列表1
Imports
System.Web.Services
Imports System.Web.Security
Imports
System.Web.Services.Protocols
Public Class SecurityContext
Inherits SoapHeader
Public userId As String
Public password As String
End
Class
<WebService(Namespace:="http://tempuri.org/")> _
Public
Class SecureWebServiceTester
Inherits
System.Web.Services.WebService
Public secureCtx As SecurityContext
<WebMethod()> Public Function HelloWorld() As String
If
Context.User.Identity.IsAuthenticated = True Then
HelloWorld = "Hello
World"
Else
HelloWorld = "Invalid User"
End If
End Function
<WebMethod(), SoapHeader("secureCtx", Required:=True,
_
Direction:=SoapHeaderDirection.InOut)> _
Public Function LoginUser()
As Boolean
If secureCtx Is Nothing Then Return False
If secureCtx.userId = "John" And secureCtx.password = "Doe"
_
Then
FormsAuthentication.SetAuthCookie(secureCtx.userId, True)
Return
True
Else
Return False
End If
End Function
End Class
SercurityContext类扩展了SoapHeader类,它告诉.NET
Framework它是一个Soap
Header并且允许在<WebMethod()>属性中被参考。主类SecureWebServicesTester包含了Web
services的实际实现了的方法,这些方法由<WebMethod()>属性标示。
LoginUser()函数接受我们的SecureContext Soap Header类的一个实例,它像使用其他对象一样使用这个传入的对象。注意对象名字在引号中被参考的,并且与secureCtx类属性匹配。
然后这个方法就通过检查usrId和secureCtx对象中的密码变量来完成验证。如果LoginUser()方法确认用户是合法的,它就产生一个验证单据,并将其插入响应的cookie集合中。
HelloWorld()方法是一个一旦客户端得到验证以后你可以在Web service中调用的一个很普通的方法。这个模式需要较少的代码,因为在一个session中只需进行一次授权,然后就可以简单地将Web service实现逻辑包装起来。
If Context.User.Identity.IsAuthenticated = True Then...
客户端实现
现在Web service已经实现并且可以运行,我们需要编写Web service消费者。这个模式的不足之处是客户端必须启用cookie以维护安全单据。典型的客户端一般都是一个Web浏览器,明显地它提供内建cookie处理功能,如果用户没有禁用它。但是如果客户端是一个桌面Windows应用程序,那么如何去访问Web service呢?列表2的示例代码给出了如何从Windows应用程序中消费Web service。
列表2
Imports
System.Net.CookieContainer
Public Class Form1
Inherits
System.Windows.Forms.Form
' Generate a cookie container object
Private cookieContainer1
As New System.Net.CookieContainer()
' Generate an instance of our Web
service
Private WSObj As New
_
SecureWebServiceTesterProxy.SecureWebServiceTester()
#Region " Windows Form Designer generated code "
Public Sub
New()
MyBase.New()
'This call is required by the Windows Form
Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent()
call
' Set our Web service's CookieContainer property to our
'
cookieContainer1 object
WSObj.CookieContainer = cookieContainer1
End
Sub
#End Region
Private Sub btnLogin_Click(ByVal sender As System.Object,
_
ByVal e As System.EventArgs) Handles btnLogin.Click
Dim secureCtx As New
_
SecureWebServiceTesterProxy.SecurityContext()
secureCtx.userId = "John"
secureCtx.password =
"Doe"
wsobj.SecurityContextValue = secureCtx
Me.lblReturnMsg.Text = "LoginUser returned: " +
_
WSObj.LoginUser().ToString
End Sub
Private Sub btnHelloWorld_Click(ByVal sender As System.Object,
_
ByVal e As System.EventArgs) Handles
btnHelloWorld.Click
Me.lblReturnMsg.Text += "HelloWorld returned: " +
_
WSObj.HelloWorld()
End Sub
End Class
要正确的实现我们的Web
service,我们必须导入(Import)System.Net.CookieContainer。这样我们就可以创建一个名为CookieContainer1的CookieContainer对象的示例,它存储Web
service中LoginUser()方法返回的验证单据。下一步我们将创建Web service自身的一个实例:
Private WSObj As
New
SecureWebServiceTesterProxy.SecureWebServiceTester().
它必须在form一级声明,因为我们的验证单据必须在Windows
Form中实现的各种方法间维护状态。至于New()方法,则是由VS.NET产生的,我们将Web
service对象的CookieContainer属性设置为cookieContainer1对象。这将告诉Web service对象使用cookie
container对象存储由Web service返回的任何cookie。
要从其它的ASP.NET应用中消费Web service,除了手工的Cookie存储代码外,其它部分的代码几乎完全一样。从一个桌面应用程序消费Web service提供了一个强大的功能、灵活性以及可扩展性。
你安全吗?
上面的代码只是一个简单的示例,说明了怎样通过编程拒绝没有合法验证单据的客户端访问Web
service来保护你的Web
service。在你的安全模型中要求的复杂级别应该由你的商业需求决定。如果应用程序中数据的敏感度比较高,那么就应该有一个测量尺度来保证你的消费者的数据尽量安全、秘密。
当然并不是所有的应用程序都需要上面的安全模式,尤其是在你的Web service可以自由使用的时候。但是其它的应用程序就需要严格安全尺度,他们的卖点就是其安全级别。