CoverStory
LANGUAGES: C#
ASP.NET VERSIONS: 1.0 | 1.1
Security
by Design
Build Secure Web Services with WS-Security
By Jeffrey Hasan
Many companies have not adopted the Web services
technology because it lacks a security specification that can ensure the
integrity of transmitted messages and data. The WS-Security specification is a joint
effort by several vendors to address this important issue.
What do we actually mean when we talk about security ? In
broad terms, we are talking about authentication and authorization:
- Authentication
is the process of validating a user s identity based on credentials, or tokens.
The token may be a username-password combination, or it may be based on an
X.509 certificate. This certificate is a signed public key that has been issued
by a certificate authority to vouch for the identity and integrity of a user.
- Authorization
is the process of allowing access to selected resources based on a user s
authenticated identity. For example, you can restrict access to a Web service s
methods by specific users.
Together, authentication and authorization provide for a
security model by allowing you to identify a user and then give them selective
access to resources.
Currently, it is possible to secure SOAP communications
over HTTP using the certificate-based Secure Sockets Layer (SSL) protocol. SSL
provides encryption and digital signing of both SOAP messages and standard HTTP
requests and responses. But SSL has two major limitations that make it
unsuitable for securing Web services communications within a service-oriented
application. First, SSL is designed for point-to-point communication. However,
service-oriented Web services may exchange SOAP messages between two or more
endpoints, and so they require a security solution that supports hops across
multiple endpoints and multiple domain boundaries. Second, the SSL protocol is
built on the HTTP protocol. Web services technology is transport-neutral, and
supports message exchange across different protocols, including TCP and SMTP,
in addition to HTTP. The SSL protocol is simply too limiting for Web services
technology.
The WS-Security specification is designed to overcome
these limitations and provide an extensible security implementation that will
evolve as the Web services technology becomes more sophisticated.
The WS-Security Specification
The prime currency in Service Oriented Architecture (SOA)
applications are SOAP messages, because they are the means by which requests
are made and responses are received from Web service methods. The WS-Security
specification provides a way for you to protect the integrity and
confidentiality of messages and to implement authentication and authorization
models in your Web services. The WS-Security specification enables you to
implement the following protections in your Web service calls:
- Authentication.
Security credentials, or tokens, may be exchanged between a client and a Web
service to validate the identity of the caller. The tokens are added directly
to the header of the SOAP message.
- Digital Signing.
This is the process of signing a SOAP message with a signature that is based on
a security token (such as an X.509 certificate). Digital signing creates a
cryptographic signature attached to the message that uniquely identifies the
sender. The receiver can check this signature to verify the identity of the
sender and the integrity of the message. A SOAP exception is raised on the
receiving end if anyone tampered with the contents of a SOAP message.
- Encryption.
This is the process of hashing a SOAP message to ensure its confidentiality.
There are many available encryption algorithms. In addition, you can encrypt a
SOAP message based on an X.509 certificate.
The WS-Security specification is platform-independent and
transport-neutral, as are all the other WS specifications. Security information
is generated by the client and stored within the envelope of the SOAP request
message. The Web service in turn will deserialize this information, verify its
validity, and process the requested operation. In the event that the message
security does not pass verification, the Web service will return a SOAP fault
back to the client.
Web Services Enhancements (WSE) 2.0 provides the API for
implementing WS-Security in .NET-based Web services and client applications. The
API allows you to write code to format secured SOAP request messages in the
client and process secured messages within a Web service.
Implement WS-Security Using WSE 2.0
The focus of this article is to show you how to write the
code to implement WS-Security in Web services and their client applications. We
will look at two examples:
1)
Digitally sign a SOAP request message with an
X.509 certificate.
2)
Encrypt a SOAP request message with an X.509
certificate.
Note that WSE 2.0 must be properly installed and configured
for the sample projects to work.
The WSE 2.0 sample projects ship with test certificates
and keys, which we will use here because they are convenient. Here are the
installation steps for the sample certificates that ship with WSE 2.0:
1)
Open the MMC console and add the Certificates
snap-in for both Current User and Local Machine.
2)
Open the Personal folder of the Current User
certificate store and import the sample personal information exchange file
entitled Client Private.pfx. This is the private key that the Web service
client will use to encrypt requests to the Web service.
3)
Open the Personal folder of the Current User
certificate store and import the sample test certificate entitled Server
Public.cer. This is the public key that the client uses to digitally sign
requests for the Web service.
4)
Open the Personal folder of the Local Machine
certificate store and import the sample test certificate entitled Server
Public.cer. This is the public key that the Web service uses to decrypt the
client s request.
After the certificates are installed, you re ready to
create Web service clients and services that exchange digitally signed and
encrypted SOAP requests. (Note that SOAP responses may also be encrypted;
however, that topic is beyond the scope of this article.)
How to Digitally Sign SOAP Messages
A digital signature is essentially a cryptographic hash
that is added to a SOAP message, and is based on a security token. Digital
signatures may be generated using several token types, including an X.509 certificate.
The certificate is used to generate a pair of related keys, called the private
and public keys. The private key is known only to the client and is used for
the following purposes:
- To digitally sign an outgoing SOAP request
message.
- To decrypt an incoming SOAP response message.
The public key is made available to authorized services,
which use it for the following purposes:
- To verify an incoming signed SOAP request
message.
- To encrypt an outgoing SOAP response message.
The digital signing process with X.509 certificates works
as follows:
1) The
client obtains an X.509 certificate and generates a private-public key pair.
The service receives a copy of the public key.
2) The
client applies a hash algorithm to the message, which creates a so-called
message digest.
3) The
client then encrypts the message digest with their private key, which creates
the digital signature.
4) The
client attaches the digital signature to the SOAP request message.
(Programmatically, WSE performs steps 3 and 4 together.)
5) The
client sends the SOAP request message out to the service.
6) The
service receives the SOAP message and checks the security token type.
7) After
the service determines that an X.509 certificate was used, it decrypts the
message signature using the public key. This process allows the service to
retrieve the original message hash. If the decryption process fails, then the
service assumes that the client is not the original sender of the message, or
the message has been tampered with, and a SOAP exception is raised.
8) The
service then generates its own message digest using the same algorithm that the
client used.
9) The
service compares its generated message digest against the one that has been
obtained from the client. If the two message digests match, then the signature
has passed verification. If it does not, then the service assumes that the
message has been tampered with and a SOAP exception is raised.
Digital signatures can have real consequences on message
delivery if they are not applied correctly, or if the verification process
fails, because either of these issues will prevent the service from processing
the incoming SOAP request message. In addition, certificates will expire, so
verification will fail if the certificate is not current. The X509SecurityToken
and X509SecurityCertificate classes both provide a Boolean IsCurrent property
that verifies whether a given certificate is still valid.
Implement a Web Service that Accepts Digitally Signed
Requests
Now let s look at an example Web service and client that
implement digital signatures. The full code listing is available for download (see
end of article for details), so to preserve space I ll simply highlight parts
of the code. Consider a Web service that provides stock ticker information. Figure
1 shows the required Web.config file settings for the Web service.
<configuration>
<configSections>
<section
name="microsoft.web.services2"
type="Microsoft.Web.Services2.Configuration.
WebServicesConfiguration,
Microsoft.Web.Services2,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=
31bf3856ad364e35"
/>
</configSections>
<system.web>
<webServices>
<soapExtensionTypes>
<add
type="Microsoft.Web.Services2.
WebServicesExtension,
Microsoft.Web.Services2,
Version=2.0.0.0,
Culture=neutral, PublicKeyToken=
31bf3856ad364e35"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
<microsoft.web.services2>
<security>
<securityTokenManager
type=
"StockTrader.CustomUsernameTokenManager,
StockTraderSecure"
xmlns:wsse=
"http://docs.oasis-open.org/wss/2004/01/
oasis-200401-wss-wssecurity-secext-1.0.xsd"
qname="wsse:UsernameToken"
/>
<x509 storeLocation="LocalMachine"
allowTestRoot="true"
allowRevocationUrlRetrieval="false"
verifyTrust="false" />
</security>
</microsoft.web.services2>
</configuration>
Figure 1:
Web.config settings for the secure Web service project.
The <security> element contains a <securityTokenManager>
sub-element that registers a custom manager class for processing security
tokens. It also contains a sub-element called <x509> with attributes that
allow this project to use unverified test root certificates. Without this
setting your Web service calls will generate a SOAP exception alerting you that
your certificate is not valid. The <x509> element also contains an
important attribute called storeLocation, which specifies the location of the
certificate that is used to validate or decrypt incoming requests.
Modify the Web Service to Process Signed SOAP Messages
The Web service must be modified to iterate through the
collection of signatures and tokens that are assigned to a SOAP request
message. It is in fact possible to add multiple tokens and signatures to a single
message, although the code listings shown here do not do this. The Web service
should process the signed SOAP message as follows:
1) Loop
through the collection of signatures attached to the SOAP message.
2) For
each signature in the collection, determine on which type of token it is based.
3) For
username tokens, implement a custom token manager to validate the token.
Figure 2 shows you how to loop through the collection of
signatures and tokens attached to a SOAP request message. Note that this code
listing is implemented directly inside the RequestQuote Web method so that a
SOAP fault may be raised directly from the method should the user fail to be
authenticated or authorized to access the method.
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using System.Xml.Serialization;
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
using System.Security.Permissions;
using StockTraderTypes;
[WebService()]
public class StockTraderService :
System.Web.Services.WebService,
IStockTrader
{
[WebMethod()]
public override Quote
RequestQuote(string Symbol)
{
// Initialize the custom token manager, in case it's needed
CustomUsernameTokenManager
objMgr =
new
CustomUsernameTokenManager();
// Verify the signature on the Web service
// request to this method
bool SignatureIsValid =
false;
SoapContext
requestContext =
RequestSoapContext.Current;
foreach (ISecurityElement
objElem in
requestContext.Security.Elements)
{
if (objElem is
MessageSignature)
{
MessageSignature
clientSignature =
(MessageSignature)objElem;
if
(clientSignature.SigningToken is X509SecurityToken)
{
SignatureIsValid =
true;
}
else if
(clientSignature.SigningToken is UsernameToken)
{
SignatureIsValid =
true;
objMgr.VerifyToken(
clientSignature.SigningToken );
}
}
}
// Proceed with request if signature is valid
Quote q = new Quote();
if (SignatureIsValid) {}
// Implementation code for RequestQuote()
}
return q;
}
Figure 2: Loop
through the collection of signatures and tokens attached to a SOAP request
message.
Create the Web Service Client
Now let s write a Web service client that generates signed
SOAP request messages. Figure 3 shows the portion of the code that retrieves an
X.509 certificate and applies it to a SOAP request message as a digital
signature.
using Microsoft.Web.Services2.Security;
using Microsoft.Web.Services2.Security.Tokens;
using Microsoft.Web.Services2.Security.X509;
X509CertificateStore store;
X509SecurityToken token;
// Open the CurrentUser Certificate Store
store = X509CertificateStore.CurrentUserStore(
X509CertificateStore.MyStore
);
// Retrieve the X509 certificate from the
// CurrentUserStore certificate store
string ClientBase64KeyId =
"gBfo0147lM6cKnTbbMSuMVvmFY4=";
X509CertificateCollection certs =
store.FindCertificateByKeyIdentifier(
Convert.FromBase64String(
ClientBase64KeyId ) );
if (certs.Count > 0)
{
// Get the first
certificate in the collection
token = new
X509SecurityToken(
((X509Certificate)
certs[0]) );
}
// Add the token and digital signature to the
// SOAP request message
serviceProxy.RequestSoapContext.Security.Tokens.Add( token );
serviceProxy.RequestSoapContext.Security.Elements.Add(
new MessageSignature(
token ) );
// Send the Web service request via the proxy class
// (Code listing not shown here.)
Figure 3:
Digitally sign a Web service request using an X.509 certificate.
Encrypt SOAP Messages with an X.509 Certificate
Security tokens and digital signing allow you to identify
a service requestor, and to determine whether a request message has been
tampered with, but they do nothing to protect the contents of a SOAP message
from network sniffers. Encryption technology enables you to generate a
cryptographic hash of the SOAP message for transport, and to decrypt the
message contents at the receiving end.
There are two kinds of encryption:
- Symmetric
encryption. Also known as private-key, or shared-secret encryption, this
method generates a cryptographic hash using a key that is known to both the
sender and the receiver. Symmetric encryption is the least secure encryption
method because both sender and receiver must share the same key, and so the
encryption is only effective if the key remains secret.
- Asymmetric
encryption. Also known as public-key encryption, this method generates a
cryptographic hash based on a private key that is known only to the sender. The
receiver is given a public key that will decrypt a message that was hashed with
the corresponding private key. Asymmetric encryption is the most secure method,
and there are many related encryption methodologies from which to choose,
including SHA1 and Triple-DES.
Interestingly enough, when a SOAP message is encrypted,
only the body of the message gets hashed. If your SOAP message includes custom
SOAP header values, then you must encrypt them separately. In the following
section we ll review how to encrypt the body of a SOAP message using asymmetric
encryption.
To get started, you can implement asymmetric encryption as
outlined in the following steps:
1) Generate
a private-public key pair based on a digital certificate.
2) Install
the private key in the client s local certificate store.
3) Install
the public key in the server s local certificate store.
4) Implement
code in the Web service client to generate an encrypted SOAP request message.
Implement the Web Service Client
The client code for generating encrypted SOAP request
messages is very similar to the code for digitally signing messages. The client
retrieves the applicable X.509 certificate-based private key from its personal
certificate store and then uses this key to generate a hash of the SOAP
message. Figure 4 shows you the required code.
public void EncryptRequestUsingX509Certificate()
{
// Retrieve the X509 certificate from the
// CurrentUserStore certificate store
X509SecurityToken token;
string ClientBase64KeyId =
"gBfo0147lM6cKnTbbMSuMVvmFY4=";
// Open the CurrentUser Certificate Store
X509CertificateStore store;
store = X509CertificateStore.CurrentUserStore(
X509CertificateStore.MyStore
);
// Find the certificate based on the server's
// base64 key identifier
X509CertificateCollection certs =
store.FindCertificateByKeyIdentifier(
Convert.FromBase64String(
ClientBase64KeyId ) );
if (certs.Count > 0)
{
// Get the first
certificate in the collection
token = new
X509SecurityToken(
((X509Certificate)
certs[0]) );
}
if (token == null) throw new ApplicationException(
"Unable to obtain
security key.");
StockTraderServiceWse serviceProxy =
new
StockTraderServiceWse();
// Add the certificate key to encrypt the request
serviceProxy.RequestSoapContext.Security.Elements.Add(
new EncryptedData( token
) );
// Call the Web service RequestQuote() method
Console.WriteLine("Calling {0}", serviceProxy.Url);
WSStockTraderClient.StockTraderEncrypted.Quote strQuote =
serviceProxy.RequestQuote("MSFT");
// Results
Console.WriteLine("Web Service call successful.
Result:");
Console.WriteLine( " " );
Console.WriteLine( "Symbol: " + strQuote.Symbol );
Console.WriteLine( "Price: " + strQuote.Last );
Console.WriteLine( "Change: " +
strQuote.PercentChange +
"%");
}
Figure 4: Encrypt
a SOAP request message using an X.509 certificate.
Certificate-based keys must be retrieved from the
certificate store using their base64 key identifier. WSE 2.0 ships with a
useful utility called the WSE X.509 Certificate Tool, which allows you to
browse certificates for the Current User and Local Machine certificate stores,
and to retrieve base64 key identifier information. Figure 5 shows the tool
displaying the client private key certificate that is used in the example shown
in Figure 4.
Figure 5: The WSE X.509 Certificate
Tool.
Modify the Web Service to Process Encrypted SOAP Messages
For asymmetric encryption, the Web service does not
require additional code for processing encrypted SOAP request messages. You
must simply ensure that the public key for decryption is installed in the Local
Machine certificate store on the same server where the Web service is
installed. If the public key is not installed correctly, the client application
will receive a SOAP fault indicating a problem on the receiving end. But if the
certificates are installed correctly, the WSE 2.0 handlers will automatically
decrypt the incoming request for you.
From a procedural standpoint you may still want to put code
in place in the Web method to verify that the request message is in fact
encrypted. Figure 6 shows the policy-oriented code listing for verifying that
an incoming request message is encrypted.
bool EncryptionIsValid = false;
SoapContext requestContext = RequestSoapContext.Current;
foreach (ISecurityElement objElem in
requestContext.Security.Elements)
{
if (objElem is
EncryptedData)
{
// Encrypted Data
exists in the Element collections.
// Now check if it is
the body that was encrypted.
EncryptedData encData
= objElem as EncryptedData;
if
(encData.TargetElement.LocalName == "Body")
{
EncryptionIsValid =
true;
// Process the Web
service request (code not shown)
}
}
}
Figure 6: Code to
verify that an incoming request message is encrypted.
Conclusion
This article has demonstrated how to use WSE 2.0 and the
WS-Security specification to implement several types of security measures in
SOAP messages, including:
- Digital signatures on SOAP messages to detect
message tampering.
- Encryption of SOAP messages (using asymmetric
encryption) to protect the contents of a SOAP message from network sniffers.
The
sample code referenced in this article is available for download.
Jeffrey Hasan is president
of Bluestone Partners, Inc., an IT solutions company based in Orange County, CA
(http://www.bluestonepartners.com).
Jeff is an experienced enterprise architect and .NET developer, and is the co-author
of several books and articles on .NET technology, including the just-released Expert Service Oriented Architecture in C#: Using the
Web Services Enhancements 2.0 (Apress, 2004). Contact Jeff at mailto:jeffh@bluestonepartners.com.