Web service protection?

Question: I have a document management system, and I create web service interfaces for the database.

Everything is working so far, right now, it is absolutely unsecured, everyone can access it.

How can I enable password or private key authentication?

I can only find “best practices” and use “Windows user” or passport authentication. But I need authentication from the user and password stored in the database, or better for the RSA private key stored for each user of the web service in the database ...

Edit:
I have to use the .NET Framework 2.0 in ASP.NET

+7
security c # web-services
source share
5 answers

The solution is to write your own http module with a mixture of code provided by MSDN and CodeProject. Including your own MS bug fixes, then add this custom soap header to the web service.

<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 
+6
source share

If you are still using the ASP.NET SOAP web service, then the easiest way that suits your requirements IMO is to use ASP.NET Forms authentication with a membership database. If you are starting a new one, I would recommend going with WCF - if you cannot / will not do this, this post refers to the "classic" ASP.NET SOAP web services.

To add forms authentication to a web service:

  • Set it up just like you would on any other website, but set it up for everyone to access:

     <authorization> <allow users="*"/> </authorization> 
  • Implement login / logout methods and issue an authentication ticket in the Login method. Further requests to the web service can then use the issued authentication ticket.

  • All other web methods you want to protect can then beautify with

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

These methods now raise a security exception if the 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 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; } 
+5
source share

If you work with WCF, there is an easy way to implement security using X509 certificates. Implementation of bindings with the "Message" security mode and clientCredentialType "Username" allows to guarantee automatic protection of this security.

Validation can be done through a class that overrides the Validate method.

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

+2
source share

Before you start your own authentication, you can look at Web Services Enhancements (WSE) 2.0 SP3 for Microsoft.NET , This is an implementation of the WS-Security specification for .net.

google wse 2.0 or WS-Security for more links.

+1
source share

If your WS will be consumed through the SOAP protocol, you can implement Security using the SOAP header:

 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, it only shows the basic aspects of using the SOAP header.

0
source share

All Articles