Securing Your .NET Web Services
By Mike Best
Published: 6/7/2002
Reader Level: Beginner
Rated: This article has not yet been rated.
Be the first to rate it!
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Security has often been the neglected stepchild of software development, but it is increasingly coming under closer scrutiny. As Web Services are deployed in greater numbers, the security of these access points into an organizations business processes can no longer be relegated to backseat status.

Generally, you will have three general security scenarios for a Web Service:

  • Those that are open to the general population, with no authentication
  • Those that are open to the general population, but with authentication
  • Those that are open to a controlled sub-set of users, such as a companys employees

    For this article, we'll assume that some sort of security is required. In addition, to simulate the scenario that will be common for many Web Services, we'll assume that the user base of our Web Services will not be confined to those users within our intranet.

    At this point it is important to define several terms that are used in the context of IIS and ASP.NET security:

  • Authentication is the process of determining the identity of the requester, and whether that identity exists within the set of known users.
  • Authorization is the process of determining if a given identity has the rights to perform a requested action.
  • Impersonation is the process of accessing resources as another user. In this case, it would be an ASP.NET application or Web Service accessing resources using a users permissions, rather than the default user account under which ASP.NET runs.

    Because .NET Web Services are based upon IIS and ASP.NET, the security model for Web Services is inherited from these technologies. However, Web Services will have different considerations than ASP.NET applications when developing a security strategy. Obviously, Web Services do not have user interfaces with which users can interact.

    You can think of the available security services as layers (see Figure 1 below). These layers sit upon one another, can be used in various combinations, and are provided by either IIS or the ASP.NET runtime. These various security implementations will be discussed in the next section.

    Figure 1: Security Layers

    IIS Authentication

    IIS provides two main security features: filtering based on IP Address and Windows-based authentication.

    IP/DNS Security

    The first layer of security that IIS provides is IP/DNS security. This is where IIS restricts or allows access to requests based upon the IP address or DNS of the requesting machine. This authentication is always the first to occur.

    IP Security can be set up on a directory or on individual files. In the IIS management console, right click on the directory or file for which you wish to set the IP security. Select Properties, and on the Security tab of the properties sheet you will find a button to edit IP Address and Domain Name Restrictions. (Note that this option will only be available on server platforms; for workstations this button will be disabled.) The form that is presented is the one in Figure 2 below. From here you can enter IP addresses or ranges, or domain names. You can make your list either inclusive or exclusive, depending upon your needs.

    Keep in mind, however, that if you choose to enter domains names, IIS will have to perform a DNS lookup, an expensive operation that could impact the performance of your site. Furthermore, if the DNS lookup fails, the client will be denied access to the site. Another point to consider is that if the clients are behind a proxy server or firewall, then only the proxy server's or firewall's IP address will be available. This will make it impossible to differentiate between these clients.

    One potential use for IP Security could be in a business-to-business (B2B) scenario, where you know the IP addresses for the machines with which you will be interacting.

    Figure 2: Setting IP Address and Domain Name Restrictions

    Windows Security

    The next layer of security provided by IIS actually consists of several different techniques, but is referred to collectively as Windows Authentication. These techniques are Basic, Digest, Integrated Windows, and Client Certificates. All of these methods rely on Windows User Accounts (which are stored in the Access Control List, or ACL); therefore each user must have a valid Windows account. This requirement limits the usefulness of Windows security for sites open to the general population.

    These Windows security methods can be used with SSL if desired. However, the use of SSL can slow server response due to the overhead of encryption, especially if large amounts of data are returned to the client.

    If you choose to open your application to users outside your immediate network, and implement a custom security solution, these Windows security options would generally not be used. For this reason, we will not discuss these methods in any more detail. However, one situation where these methods may be practical is in a B2B setting, where you are exchanging information with business partners/clients, whose numbers are small enough to allow setting up accounts for these entities with limited rights, or where you can manage the use of client certificates. For more information on Windows security, refer to the references at the end of this article.

    Once IIS has authenticated the request, it will pass that request and an authentication token to the ASP.NET runtime. If the server is set to accept anonymous users, then the IUSR_machinename account will be passed as the authentication token; otherwise, a token for the authenticated user will be passed.

    ASP.NET Security

    The last layers of security are provided by ASP.NET. To understand how this works, lets explore the process in more detail. If and when IIS succeeds in authenticating a user, it will hand an authentication token to ASP.NET along with the request. As explained in the previous section, this token will be based on the type of security IIS is enforcing. The first thing that ASP.NET will do is to verify that the user represented by the authentication token has access rights to the requested resource (e.g., aspx or asmx file), by looking up the user's access rights in the ACL. The user will either be the users actual account if authentication is enabled in IIS, or the ISUR_machinename account for anonymous access. This check will be performed regardless if ASP.NET Impersonation is enabled or not. If this check succeeds, the ASP.NET runtime will hand the request to the ASP.NET application for further processing.

    ASP.NET will now create two objects, the WindowsPrincipal and User objects, and attach them to the request. The WindowsPrincipal object contains information about the user under which the ASP.NET application code is running, and the type of authentication that was performed. The User object contains information on the User that originated the request. These values are determined by the authentication type and by whether Impersonation is on.

    Impersonation can be turned on by making the following entry in the web.config file:

    <configuration>

    <system.web>

    <!- - turn on impersonation; default is false - ->

    <identity impersonate=true/>

    </system.web>

    </configuration>

    If Impersonation is on, then the ASP.NET code will run under the User account, and be bound by that user's rights on the system. Otherwise, the code will run under the default user for ASP.NET applications: ASPNET. See the following table for possible combinations of which user account is populated in the WindowsPrincipal and User objects, and which is used by ASP.NET to perform the ACL resource check.

    Authentication Method

    Windows Principal (code runs as)

    User Identity

    Identity used for ACL Check

    Anonymous + Impersonation

    IUSR_machinename

    Null

    IUSR_machinename

    Anonymous + No Impersonation

    ASPNET

    Null

    IUSR_machinename

    Basic Authentication + Impersonation

    User Account

    User Account

    User Account

    Basic Authentication + No Impersonation

    ASPNET

    User Account

    User Account

    Now, taking this all into account, we can take a look at how IIS and ASP.NET work together to authenticate and authorize a request. Figure 3 shows the decision path that IIS and ASP.NET will follow for each request, based upon the security settings for your application.

    Figure 3: Authentication and Authorization Decision Path

    Forms Authentication

    Forms Authentication is provided by ASP.NET, mainly for Web applications. Basically, Forms Authentication checks each user request for a special authentication cookie before giving it access the requested resource. If it is not present, the user will be redirected to a login form specified with the web.config file. Once the user has been authenticated, the authentication cookie is provided, and will be supplied by the client on all subsequent requests.

    Forms Authentication can, however, be used by Web Services as well, with a few minor modifications. With these modifications, Forms Authentication becomes a custom authentication, with some of the legwork handled by ASP.NET. Like most forms of custom authentication, you will be able to authenticate and validate your users against any data store, and include custom logic as necessary. And because Forms Authentication uses HTTP calls, it can be used in conjunction with SSL. This is an important point; without the use of SSL, all information, including user ids and passwords, will be transmitted in plain text. Therefore, it is common to have at least the login page (or method) secured with SSL.

    Forms Authentication is dependent upon cookies. Without cookies being supported and enabled, clients can't be properly authenticated. An advantage of this authentication method is that much of the cookie handling is done for you. It will encrypt and decrypt the cookies automatically, once the proper settings have been made in the web.config file. Furthermore, Forms Authentication provides methods to read and write the authentication cookies.

    As mentioned above, several adjustments must be made to use Forms Authentication for Web Services; these must be made in the web.config file. The first section to update is the "authentication" element. The mode attribute must be set to "Forms." Within this element, a "forms" element must be added. The name attribute is the name of the authentication cookie that will be written out to the client. The loginUrl attribute is the page that the client will be redirected to if the authentication cookie is not present. In the case of Web Services, we do not want a redirect to take place; therefore, we will put the name of our Web Service, so the call will be redirected back to the Web Service. The protection attribute (possible values are: All, Encryption, Validation, None) is used to protect the authentication cookie. A setting of 'All' will perform both validation and encryption. 'Validation' will compare the cookie against the original content placed in the cookie, and 'Encryption' will encrypt the authentication cookie using the 3DES algorithm. Only the cookie, however, is encrypted. If sensitive data needs to be protected, SSL should be used. The timeout attribute will determine how long the cookie will be valid after the last request. The default is 30 minutes.

    <authentication mode="Forms">

    <forms name="CookieName" loginUrl="Products.asmx" protection="All" timeout="60" path="/" />

    </authentication>

    The "authorization" element of the web.config file must also be updated. We must remove the "allow" element and replace it with a "deny" element with a users attribute. This will cause ASP.NET to deny authorization for the specified users. The '?' value indicates all anonymous users; a '*' would indicate all users.

    <authorization>

    <deny users="?" />

    </authorization>

    Now that we've configured ASP.NET to support Forms Authentication for our Web Service, let's take a look at the Web Service itself.

    The first thing that we will do is to import the System.Web.Security namespace; this will give us access to the Forms Authentication objects.

    Imports System.Web.Security

    Next, we will look at the Login method. This method must be called by the client before any other methods on this Web Service can be called. The Login method will place an authentication token cookie on the client, which will be checked by the other methods in the Web Service before they run.

    <WebMethod()> Public Function Login(ByVal UserName As String, ByVal Password As String) As Boolean

    If UserName.Length > 0 And Password.Length > 0 Then>

    FormsAuthentication.SetAuthCookie(UserName, True)

    Return True

    Else

    Return False

    End If

    End Function

    This sample code uses a very simplistic method for validating the user's UserName and Password, merely checking that their length is greater than 0. In a production application, this could be replaced with a check against a database or any other data store where user account information is kept. If the validation is successful, the SetAuthCookie method of the FormsAuthentication object (from the System.Web.Security namespace imported above) is used to add an authentication cookie to the clients cookie collection. The second parameter is used to specify whether the cookie is persistent, that is, if it lives beyond the current browser session.

    Note that since the token is sent back as a cookie, the client must support cookies and have them enabled. This is not an issue for browser clients, but rich win32 clients do not support cookies by default. We will address this concern in the next section, which discusses the client application.

    Now let's look at a function within the Web Service that contains business logic we wish to protect. This is the method for which we implemented security in the first place. The function returns a product name given a product ID. The first thing the function does is to verify that the user has been authenticated. If the user has already run our login procedure, then Context.User.Identity.IsAuthenticated will be True, so we can run our logic to return the product name. Otherwise, we can return an error code or message, indicating that the user has not been authenticated.

    The User property of the Context (or HTTPContext) object gets or sets security information for the current HTTP request. The Identity property is the Identity object associated with the current principal. The Context.User.Identity object also exposes a AuthenticationType property, which contains the authentication type for this user. The AuthenticationType would be 'Forms' in this example.

    <WebMethod()> Public Function ProductName(ByVal ProductID As String) As String

    If Context.User.Identity.IsAuthenticated = True Then

    Return "Pet Rock"

    Else

    Return "Need to Login"

    End If

    End Function

    One other method I have included in this Web Service is the Logout method. This method will remove the authentication cookie from the client machine, and can be used to increase the amount of control we have over the lifetime of the user's authenticated session. Otherwise, the lifetime of the cookie would be dictated by the SetAuthCookie method called in Login, and would either be permanent, or would expire when the browser session ended.

    <WebMethod()> Public Function Logout()

    If Context.User.Identity.IsAuthenticated = True Then

    FormsAuthentication.SignOut()

    End If

    End Function

    Client Application

    Let's take a quick look at our rich client. It is a simple Winforms application that consumes our Web Service. Each of the buttons on the form will call one of the methods our our Web Service.

    Figure 4: Win32 Client for the Products Web Service

    Because our Web Service depends on cookies to track authenticated users, we need to add the ability for our application to handle cookies. To do this, we need to reference the CookieContainer namespace:

    Imports System.Net.CookieContainer

    The cookiecontainer object is used to hold our cookie collection. Because our application will need this object over its lifetime, not just for the lifetime of a single method, the cookiecontainer is declared globally for the form. We will also need to create an instance of our Web Service. To do this, we will first need to add a Web Reference to our client application by right-clicking the client project in the Solution Explorer, and selecting the Add Web Reference menu item. An Add Web Reference dialog will appear; type the URL of the Web Service into the Address field. Once the Web Service has been found, and its methods have been listed, select the Add Reference button. This will add the Web Reference to your project, and in so doing, create several files. These include wsdl and disco files, as well as a proxy file, named Reference.vb by default. You can rename the Web Reference, and in this case, our Web Reference has been named FormsAuth. This will be the name used when creating instances of the Web Service.

    Private cookieContainer1 As New System.Net.CookieContainer()

    Private wsForms As FormsAuth.Products = New FormsAuth.Products()

    Because our wsForms variable is of type Web Service, it contains a property called CookieContainer. We must set this property to the cookieContainer object that we created declared above. This code has been placed in the constructor of our form object, so that it is run once at startup.

    wsForms.CookieContainer = cookieContainer1

    Our client application has two buttons: one to run the Web Service's Login function, and one to run the ProductName function. The code to run these functions is simple. To run the Login method, we have to pass a UserName and Password, which we are getting from two TextBoxes on our client form:

    Label1.Text = wsForms.Login(TextBox1.Text, TextBox2.Text).ToString

    Likewise, the ProductName method requires a ProductID argument, which we are getting from TextBox3:

    Label1.Text = wsForms.ProductName(TextBox3.Text)

    By first running the Login method, and then the ProductName method, you will be able to see the appropriate output on the screen. If however, the ProductName method is run without first being authenticated, you will see a message indicating that you need to login.

    Summary

    This article explains the basics of IIS and ASP.NET security, and shows how Forms Authentication can be used to help secure Web Services. While this article does not discuss them, other methods of securing Web Services can be used, such as:

  • Requiring a user id and password for every method call, instead of using a login method
  • Creating a custom cookie to send to the client machine, instead of using the cookie generated by Forms Authentication
  • Using a login method to generate a custom token to pass to the client, and require that this token be returned as a parameter in all subsequent method calls. This token could be time dependent, and appropriately encrypted/hashed to provide an extra level of security.

    Security is a critical consideration when designing and implementing web services. If one of these methods will not work for your situation, be sure that some form of security is in place.

    References

  • Authentication in ASP.NET: .NET Security Guidance
    (http://msdn.microsoft.com/library/en-us/dnbda/html/authaspdotnet.asp)

  • An Introductory Guide to Building and Deploying More Secure Sites with ASP.NET and IIS (http://msdn.microsoft.com/msdnmag/issues/02/04/ASPSec/ASPSec.asp)

  • IIS Documentation on Authentication, Certificates, and Encryption



  • Marketplace
    (Sponsored Links)
    What are the green links?
       



     
    Copyright © 2007 CMP Tech LLC |
    Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help