< VB .NET Service Point Program Example | Main | C++ Authentication Program Example >

 


 

Chapter 10 Part 15:

HTTP with .NET

 

 

What do we have in this chapter 10 Part 15?

  1. Secure Connections

  2. Authentication

  3. Unsafe Authentication

  4. Secure Socket Layer (SSL)

  5. Certificates

 

 

Secure Connections

 

A Web site is often structured to restrict access to authorized users or encrypt the data stream to prevent prying eyes from viewing sensitive information. The .NET Framework Web classes support several methods of security.

First, a request can contain user information that authenticates the request. The .NET Framework supports several authentication methods such as NTLM and Kerberos, but it is also extensible so that other authentication technologies can be added. Secondly, encrypted connections can be created by sending a request using the Secure Sockets Layer (SSL) protocol. The next couple sections in this chapter discuss these concepts in more detail.

 

Authentication

 

Many Web pages restrict access to authorized users in order to protect sensitive personal information or to safeguard services for pay, for example. Providing authentication information with a request is simple: an instance of the NetworkCredential class is created with the user and password information and is then associated with the request object via the Credentials property of the WebRequest and HttpWebRequest classes. An instance of a CredentialCache object also can be assigned to the Credentials property. This class is a container for multiple credentials, which we’ll talk about later in this section.

The NetworkCredential class has several constructors that take a combination of username, password, and domain. These values are exposed as the properties UserName, Password, and Domain. The following code shows how to create credentials and associate them with an HTTP request:

 

C#

 

HttpWebRequest    httpRequest;

HttpWebResponse   httpResponse;

 

httpRequest = (HttpWebRequest) WebRequest.Create("http://payroll");

httpRequest.Credentials = new NetworkCredential("joe", "password", "DOMAIN");

httpResponse = (HttpWebResponse) httpRequest.GetResponse();

 

Visual Basic .NET

 

Dim httpRequest As HttpWebRequest

Dim httpResponse As HttpWebResponse

 

httpRequest = WebRequest.Create("http://payroll")

httpRequest.Credentials = New NetworkCredential("joe", "password", "DOMAIN")

httpResponse = httpRequest.GetResponse() 

 

When a request is made with security credentials, multiple security providers might be installed, such as NTLM, Kerberos, etc. When the Web request is issued and a challenge is returned from the server, each installed security provider is queried until one accepts the challenge and returns a valid Authorization class object. These providers are queried in the order they are registered with the .NET Framework and the AuthenticationManager class.

The AuthenticationManager is a static class that can be used to enumerate the registered security providers or to register a custom security provider. The AuthenticationManager maintains an ordered collection of providers that can be queried by accessing the RegisteredModules property. The following code illustrates this scenario:

 

C#

 

IEnumerator               registeredModules;

IAuthenticationModule    currentModule;

 

registeredModules = AuthenticationManager.RegisteredModules;

Console.WriteLine("Authentication Modules:");

 

while( registeredModules.MoveNext() )

{

    currentModule = (IAuthenticationModule)registeredModules.Current;

 

    Console.WriteLine("   Module : {0}", registeredModules.Current);

    Console.WriteLine("    Supports Pre-Authentication : {0}", currentModule.CanPreAuthenticate );

}

 

Visual Basic .NET

 

Dim registeredModules As IEnumerator

Dim currentModule As IAuthenticationModule

 

registeredModules = AuthenticationManager.RegisteredModules

Console.WriteLine("Authentication Modules:")

 

While (registeredModules.MoveNext())

    currentModule = registeredModules.Current

    Console.WriteLine("   Module : {0}", registeredModules.Current)

    Console.WriteLine("    Supports Pre-Authentication : {0}", currentModule.CanPreAuthenticate)

End While

 

It is possible to plug in custom authentication schemes. This is accomplished by creating a class that implements the IAuthenticationModule interface. The interface requires two methods and two read-only properties to be implemented. The two read-only properties are:

 

  1. AuthenticationType: This string is a read-only property that returns the authentication scheme name.
  2. CanPreAuthenticate: This Boolean read-only property indicates whether the authentication module supports pre-authentication.

 

The two methods are:

  1. public Authorization PreAuthenticate(WebRequest request, ICredentials credentials)

  2. public Authorization Authenticate(String challenge, WebRequest request, ICredentials credentials)

 

The PreAuthenticate() method is used when the authentication scheme allows a user to be pre-authenticated. Pre-authentication is enabled when the PreAuthenticate property of a WebRequest or HttpWebRequest is set to true. For those security schemes that support pre-authentication, this causes the “WWW-authenticate” header to be sent with the request that supplies the credential information so that subsequent requests do not have to specify the same information again.

If the given security scheme doesn’t support pre-authentication, the PreAuthenticate() method still must be implemented but should return null (or Nothing in Visual Basic .NET). Both the PreAuthenticate() and Authenticate() methods return an Authorization object containing the encrypted message that is expected by the server and sent with the request. An Authorization object is constructed by passing the generated authentication string to the constructor.

For the Authenticate() method, the input parameter challenge contains the string indicating the type of authentication required. The Authenticate() method should verify whether to handle the authorization request based on the challenge string. If so, it returns a valid Authorization object, and if not, it returns null or Nothing. The credentials parameter is the NetworkCredential object associated with the Web request used in the authentication process.

The PreAuthenticate() method is called for providers that support pre- authentication after the Authenticate() method has been called in response to a challenge. This method takes the WebRequest object on which the pre-authentication is taking place along with the credentials associated with the request.

As mentioned earlier in this section, a CredentialCache object can be used to track different user credentials for different URIs. This relieves the burden on the application of having to set up a NetworkCredential object for each request. After a CredentialCache object is created, a NetworkCredential instance is added via the Add() method along with the URI on which the credentials are to be used and the authentication scheme for the credentials, such as “Basic,” “Digest,” or “NTLM.” Remember, the AuthenticationManager can enumerate the available authentication schemes. Take note that while this section shows you how to associate credentials with each request, it is recommended that CredentialCache.DefaultCredentials be used instead as it supplies the current user’s credentials (including whether the application is impersonating someone else). This use of DefaultCredentials prevents the application from having to prompt for a user’s password, which can lead to security vulnerabilities. Also, note that DefaultCredentials only applies to NTLM- and Kerberos-based authentication.

 

Unsafe Authentication

 

Under normal circumstances, NTLM authentication occurs on the connection level, not for each individual request. This means that if the client application impersonates a different user after the initial authentication, subsequent requests that should be from different users will be made in the context of the original authenticated user. Because of this potential security hole, the .NET Framework Web classes authenticate on every request, not just the first.

Of course, this behavior can degrade performance, especially if no impersonation is taking place. Because of this, the HttpWebRequest Boolean property UnsafeAuthenticatedConnectionSharing is exposed to disable the behavior. If this property is set to true, it is important to ensure that the application doesn’t blindly use impersonation. If impersonation is required, the ConnectionGroupName string property provides a way to partition different request into groups. All the requests associated with a single user should contain the same ConnectionGroupName, as this allows the correct authentication credentials to be sent for each group.

 

Secure Socket Layer (SSL)

 

One of the great advantages to using the .NET Framework Web classes is that SSL support is nearly transparent. The only difference between a normal request and an SSL-encrypted request is that https is the URI scheme instead of http. The SSL negotiation that occurs to establish the underlying connection, send the request, and retrieve the response is transparent and requires no intervention by the application. In NET Framework version 1 only SSL 3 and not TLS 1 is used for requests. This is a confirmed bug. See Knowledge Base article 330965. Any of the HTTP request program examples in this chapter can be used to retrieve a URI with the https scheme.

 

 

Certificates

 

Certificates are a part of the authentication process when using public and private key security technologies, such as SSL. The .NET Framework supports the use of X.509 version 3 certificates, which are a mechanism for validating that the private and public keys used to access a resource are correct. In this section we’ll discuss methods for associating a specific certificate with a request in addition to programming considerations when using X.509 certificates. However, a discussion of how certificate validation occurs is beyond the scope of this book. For more information on X.509 certificates consult RFC2459 or a cryptography book.

The HttpWebRequest class allows specific certificates to be associated with the request by the ClientCertificates property, which is an X509CertificateCollection object. Individual X509Certificate objects can be added to or removed from the X509CertificateCollection via the Add() and Remove() methods. An X509Certificate object is created one of several ways. Using the constructor, an X509Certificate can be created from a byte array representing the actual X.509 certificate, from a handle to an existing certificate, or from an already created X509Certificate class.

Alternately, the static methods CreateCertFromFile() and CreateCertFromSignedFile() return X509Certificate objects when given the path and filename to a valid certificate file. Notice that only the ASN.1 DER format for X.509 certificates is supported regardless of which method is used to create a certificate object.

There are several considerations when using certificate objects. First, the X509Certificate created is only a reference to the certificate within the certificate store, not the actual certificate. This is important if impersonation is used, as accessing the X509Certificate might fail if the current user does not have the correct rights. Of course, the Access Control Lists (ACLs) can be set on the certificate store, as well as on the certificate itself, to allow a different user to access the certificate.

Secondly, when a certificate is referenced, the certificate store for the current user, the “My” store, is accessed followed by the machine store. However, the My store is often unavailable in middle-tier scenarios, such as ASP.NET. Because of this, if a certificate is accessed from a process that does not have access to the My store, the operation will fail, an exception will be generated, and the machine store will not be queried. A fix to this problem is available for version 1 of the .NET Framework as a QFE (Quick Fix Engineering). This is described in Knowledge Base article 817854.

As mentioned earlier, a primary reason for using certificates is to validate the public and private keys match. It is also important to validate the X.509 certificate because a certificate can expire, be revoked, or have other problems. Certificate verification is handled differently depending on the .NET Framework version. For example, version 1 of the .NET Framework did not check for certificate revocation or certificate name (CN) mismatches. Additionally, in the .NET Framework versions that support checking for certificate revocation, the feature is disabled by default. To enable this feature, the ServicePointManager.CheckCertificateRevocationList property must be set to true. Certificate revocation checking and CN mismatch checking also can be enabled globally through the machine.config file or for a specific application by the configuration file.

Finally, an application can define its own certificate policy by implementing the ICertificatePolicy interface and assigning it to the ServicePointManager.CertificatePolicy property. It is not recommended to override the default policy, however, as this could lead to potentially dangerous security problems. There is a single method for the ICertificatePolicy interface, which is CheckValidationResult(), as shown in the following sample:

 

C#

 

bool CheckValidationResult(

    ServicePoint srvPoint,

    X509Certificate certificate,

    WebRequest request,

    int certificateProblem

);

 

Visual Basic .NET

 

Function CheckValidationResult( _

    ByVal srvPoint As ServicePoint, _

    ByVal certificate As X509Certificate, _

    ByVal request As WebRequest, _

    ByVal certificateProblem As Integer _

) As Boolean

 

The CheckValidationResult() simply returns a Boolean value indicating whether to accept or reject the certificate. The parameters to the function are X509Certificate and ServicePoint, which will use the certificate along with the WebRequest that received the request. The certificateProblem parameter is the error code encountered while using the certificate. CheckValidationResult() must determine whether the error code truly is a failure according to the custom policy. The actual error codes are dependent on the underlying security packages defined by the Security Support Provider Interface (SSPI). Consult the platform SDK for detailed information on SSPI, its security providers, and their error codes. The CheckValidationResult method determines whether the returned error is truly an error or should be ignored. Returning true indicates the certificate should be honored, whereas returning false causes the request to fail. Take note that ASP.NET applications cannot set a client certificate when calling a secure Web service. This is a confirmed bug in the .NET Framework. See Knowledge Base article 817854.

 

 

 


 

< VB .NET Service Point Program Example | Main | C++ Authentication Program Example >