简体   繁体   English

保护Web服务?

[英]Securing a web service?

Question: I have a document management system, and I am building a Web-Service interfaces to the database. 问题:我有一个文档管理系统,我正在构建一个到数据库的Web服务接口。

Everything works so far, just that right now, it's totally unsecured, everybody can access it. 到目前为止一切都有效,就在现在,它完全没有安全感,每个人都可以访问它。

How can I incorporate password or private-public key authentication ? 如何合并密码或私钥 - 公钥认证?

I can only find 'best practises' and using 'windows user' or passport authentication. 我只能找到'最佳实践'并使用'windows user'或护照验证。 But I need authentication from a user and password stored in the database, or better for an RSA private-key stored for each web-service user in the database... 但是我需要来自用户的身份验证和存储在数据库中的密码,或者更好的是为数据库中的每个Web服务用户存储的RSA私钥...

Edit: 编辑:
I have to use the .NET Framework 2.0 in an ASP.NET environment 我必须在ASP.NET环境中使用.NET Framework 2.0

The solution is to write an own http module with a mixture of code provided by MSDN and CodeProject. 解决方案是使用MSDN和CodeProject提供的混合代码编写自己的http模块。 Including own fixes of MS bugs, and then add this custom soap header to the web service. 包括自己的MS错误修复程序,然后将此自定义soap标头添加到Web服务。

<SoapHeader("Authentication", Required:=True)>

This is the module: 这是模块:

Imports System.Web
Imports System.Web.Services.Protocols


' http://msdn.microsoft.com/en-us/library/9z52by6a.aspx
' http://msdn.microsoft.com/en-us/library/9z52by6a(VS.80).aspx




' http://www.codeproject.com/KB/cpp/authforwebservices.aspx


' http://aleemkhan.wordpress.com/2007/09/18/using-wse-30-for-web-service-authentication/
' http://www.codeproject.com/KB/WCF/CustomUserNamePassAuth2.aspx
' http://www.codeproject.com/KB/WCF/CustomUserNamePassAuth2.aspx
' http://www.codeproject.com/KB/webservices/WS-Security.aspx




'Public NotInheritable Class WebServiceAuthenticationModule
Public Class WebServiceAuthenticationModule
    Implements System.Web.IHttpModule

    Protected Delegate Sub WebServiceAuthenticationEventHandler(ByVal sender As [Object], ByVal e As WebServiceAuthenticationEvent)
    Protected _eventHandler As WebServiceAuthenticationEventHandler = Nothing



    Protected Custom Event Authenticate As WebServiceAuthenticationEventHandler
        AddHandler(ByVal value As WebServiceAuthenticationEventHandler)
            _eventHandler = value
        End AddHandler
        RemoveHandler(ByVal value As WebServiceAuthenticationEventHandler)
            _eventHandler = value
        End RemoveHandler
        RaiseEvent(ByVal sender As Object,
                ByVal e As WebServiceAuthenticationEvent)
        End RaiseEvent
    End Event


    Protected app As HttpApplication


    Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
        app = context

        context.Context.Response.Write("<h1>Test</h1>")

        AddHandler app.AuthenticateRequest, AddressOf Me.OnEnter
    End Sub


    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose
        ' add clean-up code here if required
    End Sub


    Protected Sub OnAuthenticate(ByVal e As WebServiceAuthenticationEvent)
        If _eventHandler Is Nothing Then
            Return
        End If
        _eventHandler(Me, e)
        If Not (e.User Is Nothing) Then
            e.Context.User = e.Principal
        End If

    End Sub 'OnAuthenticate 


    Public ReadOnly Property ModuleName() As String
        Get
            Return "WebServiceAuthentication"
        End Get
    End Property


    Sub OnEnter(ByVal [source] As [Object], ByVal eventArgs As EventArgs)
        'Dim app As HttpApplication = CType([source], HttpApplication)
        'app = CType([source], HttpApplication)
        Dim context As HttpContext = app.Context
        Dim HttpStream As System.IO.Stream = context.Request.InputStream

        ' Save the current position of stream.
        Dim posStream As Long = HttpStream.Position

        ' If the request contains an HTTP_SOAPACTION 
        ' header, look at this message.

        'For Each str As String In context.Request.ServerVariables.AllKeys

        'If context.Request.ServerVariables(Str) IsNot Nothing Then
        'context.Response.Write("<h1>" + Str() + "= " + context.Request.ServerVariables(Str) + "</h1>")
        'End If
        'Next
        If context.Request.ServerVariables("HTTP_SOAPACTION") Is Nothing Then
            'context.Response.End()
            Return
            'Else
            'MsgBox(New System.IO.StreamReader(context.Request.InputStream).ReadToEnd())
        End If


        ' Load the body of the HTTP message
        ' into an XML document.
        Dim dom As New System.Xml.XmlDocument()
        Dim soapUser As String
        Dim soapPassword As String

        Try
            dom.Load(HttpStream)

            'dom.Save("C:\Users\Administrator\Desktop\SoapRequest.xml")
            ' Reset the stream position.
            HttpStream.Position = posStream

            ' Bind to the Authentication header.
            soapUser = dom.GetElementsByTagName("Username").Item(0).InnerText
            soapPassword = dom.GetElementsByTagName("Password").Item(0).InnerText
        Catch e As Exception
            ' Reset the position of stream.
            HttpStream.Position = posStream

            ' Throw a SOAP exception.
            Dim name As New System.Xml.XmlQualifiedName("Load")
            Dim ssoapException As New SoapException("Unable to read SOAP request", name, e)
            context.Response.StatusCode = System.Net.HttpStatusCode.Unauthorized
            context.Response.StatusDescription = "Access denied."

            ' context.Response.Write(ssoapException.ToString())
            'Dim x As New System.Xml.Serialization.XmlSerializer(GetType(SoapException))
            'context.Response.ContentType = "text/xml"
            'x.Serialize(context.Response.OutputStream, ssoapException)


            'Throw ssoapException

            context.Response.End()
        End Try

        ' Raise the custom global.asax event.
        OnAuthenticate(New WebServiceAuthenticationEvent(context, soapUser, soapPassword))
        Return
    End Sub 'OnEnter


End Class ' WebServiceAuthenticationModule

If you are still using an ASP.NET SOAP web service then the easiest way that fits your requirements IMO is to use the ASP.NET Forms authentication with a Membership DB. 如果您仍在使用ASP.NET SOAP Web服务,那么符合您要求的最简单方法IMO就是将ASP.NET Forms身份验证与Membership DB一起使用。 If you are starting out fresh I'd recommend going with WCF - if you can't/or won't do that this post applies to the "classic" ASP.NET SOAP web services. 如果你刚刚开始新的我建议使用WCF - 如果你不能/或不会这样做,这篇文章适用于“经典”的ASP.NET SOAP Web服务。

To add Forms authentication to a web service: 要向Web服务添加Forms身份验证:

  1. Configure it just like you would for any other web site but set it to allow access for everyone: 像对待任何其他网站一样配置它,但将其设置为允许每个人访问:

     <authorization> <allow users="*"/> </authorization> 
  2. Implement Login/Logout methods and issue the authentication ticket in the Login method. 实现Login / Logout方法并在Login方法中发出身份验证票证。 Further requests to the web service then can use the issued authentication ticket. 然后,对Web服务的进一步请求可以使用所发布的认证票证。

  3. All other web methods you want to protect you can then decorate with 您想要保护的所有其他Web方法随后可以装饰

    [PrincipalPermission(SecurityAction.Demand, Authenticated = true)] [PrincipalPermission(SecurityAction.Demand,Authenticated = true)]

These methods will now throw a Security exception if a client is not authenticated. 如果客户端未经过身份验证,这些方法现在将抛出安全性异常。

Example for a protected method: 受保护方法的示例:

[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
[WebMethod(Description = "Your protected method")]
public string Foo()
{
    return "bar";
}

Example for Login method: 登录方法示例:

[WebMethod(Description = "Login to start a session")]
public bool Login(string userName, string password)
{
    if (!Membership.Provider.ValidateUser(userName, password))
        return false;

    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
           1,
           userName,
           DateTime.Now,
           DateTime.Now.AddMinutes(500),
           false,
           FormsAuthentication.FormsCookiePath);// Path cookie valid for

    // Encrypt the cookie using the machine key for secure transport
    string hash = FormsAuthentication.Encrypt(ticket);
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, // Name of auth cookie
                                       hash); // Hashed ticket

    // Set the cookie's expiration time to the tickets expiration time
    if (ticket.IsPersistent)
        cookie.Expires = ticket.Expiration;

    // Add the cookie to the list for outgoing response
    if(HttpContext.Current !=null)
        HttpContext.Current.Response.Cookies.Add(cookie);

    FormsAuthentication.SetAuthCookie(userName, true);
    return true;
}

If you are working with WCF, there's an easy way to implement security using X509 certificates. 如果您正在使用WCF,则可以使用X509证书轻松实现安全性。 Implementing a binding with security mode 'Message' and clientCredentialType 'Username' it's possible to guarantee this security in a automated way. 使用安全模式“Message”和clientCredentialType“Username”实现绑定,可以以自动方式保证此安全性。

The validation can be made through a class wich overrides a method Validate. 可以通过覆盖方法Validate的类来进行验证。

http://msdn.microsoft.com/en-us/library/aa702565.aspx http://msdn.microsoft.com/en-us/library/aa702565.aspx

Before you roll your own authentication, you might want to have a look at Web Services Enhancements (WSE) 2.0 SP3 for Microsoft .NET . 在您自己进行身份验证之前,您可能需要查看适用于Microsoft .NET的Web服务增强功能(WSE)2.0 SP3 It's an implementation of the WS-Security specification for .net. 它是.net的WS-Security规范的实现。

google wse 2.0 or WS-Security for more links. google wse 2.0WS-Security获取更多链接。

If your WS is going to be consumed through SOAP protocol, the you can implement the Security through the SOAP Header: 如果您的WS将通过SOAP协议使用,您可以通过SOAP Header实现Security:

using System.Web.Services;
using System.Web.Services.Protocols;

namespace Domain.WS
{
    [Serializable]
    public class SoapWSHeader : System.Web.Services.Protocols.SoapHeader, ISoapWSHeader
    {
        public string UserId { get; set; }
        public string ServiceKey { get; set; }
        public ApplicationCode ApplicationCode { get; set; }        
    }    

    [WebService(Namespace = "http://domain.some.unique/")]        
    public class MyServices : System.Web.Services.WebService
    {
        public SoapWSHeader WSHeader;
        private ServicesLogicContext _logicServices;

        public MyServices() { _logicServices = new ServicesLogicContext(new LogicInfo() {...}); }

        [WebMethod, SoapHeader("WSHeader", Direction = SoapHeaderDirection.InOut)]
        public Result WSMethod1(Int32 idSuperior)
        {
            _logicServices.ThrowIfNotAuthenticate(WSHeader); 
            return _logicServices.WSMethod1(idSuperior) as Result;
        }
    }
}

namespace Domain.Logic 
{
    [Serializable]    
    public class ServicesLogicContext : ServicesLogicContextBase
    {
        protected ISoapWSHeader SoapWSHeader { get; set; }
        public ServicesLogicContext(LogicInfo info) : base(info) {}

        public IResult WSMethod1(Int32 idSuperior)
        {
            IResult result = null; 
            //-- method implementation here...
            return result;
        }

        public void ThrowIfNotAuthenticate(ISoapWSHeader soapWSHeader) {
            this.SoapWSHeader = soapWSHeader;
            if (SoapWSHeader != null)
            {
                if (!ValidateCredentials(soapWSHeader))
                {
                    throw new System.Security.SecurityException(Resources.ValidationErrorWrongCredentials);
                }
            }
            else { throw new System.Security.SecurityException(Resources.ValidationErrorWrongWSHeader); }
        }
        private bool ValidateCredentials(ISoapWSHeader soapWSHeader) {   
            return (SoapWSHeader.UserId.Equals("USER_ID") && SoapWSHeader.ServiceKey.Equals("PSW_1"));
        }
    }
}

Note: this code is not complete, this only depicts the main aspects on how to use the SOAP Header. 注意:此代码不完整,这仅描述了如何使用SOAP Header的主要方面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM