1. Web Services Security introduction.
Security is a very important aspect in everyday enterprise application. There are several solutions for securing Web Services applications, all of them were transport-protocol based such as IPSec or https through Public Key Infrastructure. Those protocols have the drawback they provide a point-point service.
As part of the evolution and stabilization of Web Services specifications, the WS-Security related specifications appears as a message-based security protocol, they allow providing an end-to-end service, regarding the intermediaries.
WS-Security related specifications cover well-known approaches to follow on the developing a Web Services security specification such as security at granularity level of the message, authentication (using authentication tokens to validate requester identity), authorization (assertion to control access to the provider service), non-repudiation (using digital signature to protect against altering transmitted information) and encryption (for protecting against seeing transmitted information).
In this article, we are going to learn the basic concepts of WS-Security related specifications and how they are implemented by Microsoft Web Service Enhancements 3.0 technology.
1.1 WS-Security specification.
WS-Security specification was established as an approved OASIS open standard in April, 2004.
Creating and managing a secure Web services environment involves dealing with various Internet, XML, and Web services security mechanisms.
The WS-Security specification describes how to incorporate security mechanisms on the Web Services protocol stack as extensions to the SOAP headers. The headers can include authentication, encryption, and signature so that the provider can validate the credentials (security tokens proving identity) of the requester before executing the service. Invalid credentials result return of a fault message to the requester.
The WS-Security specification provides a framework where other security technologies can be plugged for protecting messages. For example, it is not defined any authentication mechanism; instead, it is defined how to transmit a variety of different security tokens using the security header, such as user name/password, Kerberos, and X.509 credentials.
The WS-Security specification also defines how to use XML Signature (for message integrity), and XML Encryption (for message confidentiality). The message integrity is verified to ensure that the messages are being transmitted without any changes. This integrity mechanism allows multiple signatures included the one added by intermediaries. The signature also verifies the claim that the message comes from the right requester. The message encryption allows confidentiality.
1.2 Other related Web Services security specifications.
There are other Web services security specifications, such as WS-Trust, WS-Secure-Conversation, WS-Federation and WS-SecurityPolicy.
WS-Trust, WS-Secure-Conversation, WS-Federation define protocols for establishing agreements between services requesters and providers.
WS-SecurityPolicy specification is used to declare the provider's requirements for security support. It is a policy assertion language that can be used in conjunction to WS-Policy specification. It allows defining assertions associated to a Web Service endpoint. A service requester can discover the WS-SecurityPolicy association using the WS-MetadataExchange protocol or referencing the address of the XML file in which the WS-SecurityPolicy assertion is stored.
The WS-Trust specification defines a process of exchanging security tokens among the parties that participate in the secure communication. A requester may need to obtain the provider's public key for encryption before sending the message. It complements WS-Security with protocols for requesting, issuing, and brokering (delegation, forwarding) security tokens. Network and transport protection (IPSec and TLS/SSL) mechanisms can be used with WS-Trust for different requirements. Security token acquisition can be done directly by explicitly requesting one from an appropriate issuer, or indirectly by delegating the acquisition to a trusted third party. Tokens can also be acquired out-of-band. The specification also uses a mechanism to reference security tokens in those situations when it is advisable to return a security token as part of the security header defined by WS-Security.
The WS-Secure Conversation specification defines a shared context for exchanging messages among the communication parties.
The WS-Federation specification defines how to establish trust relationships across security domains accepting authentication credentials that come from a different security domain (realm).
2. WSE 3.0 Introduction.
Web Services Enhancement version 3.0 (WSE 3.0) is a framework for extending the basic SOAP messaging and supporting emerging new WS-* specifications. WSE 3.0 simplifies the creation of secure, interoperable and scalable Web services and it ships with a design time tool (WSE Settings 3.0) that fully integrates with Visual Studio 2005.
WSE 3.0 allows you to apply security at a higher level of end-to-end messages using policies which are a set of security rules applied to incoming and outgoing messages known as security assertions.
The policy implementation in WSE 3.0 is based on the WS-SecurityPolicy and WS-PolicyAssertion specifications. These policies are used to provide confidentiality, integrity and data origin authentication. It is possible to add capabilities using code or a policy file.
WES 3.0 actually implements the following Web Services specifications grouped by enterprise aspects:
- Web Services Security.
- SOAP Message Security (WS-Security) version 1.0 and version 1.1.
- Web Services Secure Conversation Language (WS-SecureConversation).
- Web Services Trust Language (WS-Trust).
- Web Services Security X.509 Certificate Token Profile.
- Web Services Security UsernameToken Profile 1.0
- Web Services Security Kerberos Token Profile 1.0
- Web Services Addressing.
- Web Service Addressing (WS-Addressing).
- Web Services Messaging.
- SOAP Message Transmission Optimization Mechanism (MTOM)
- SOAP version 1.1 and version 1.2
There are five common scenarios for message level security, and WSE 3.0 provides for them a set of defined security assertions that are called turnkey security assertions.
Turnkey security assertions are requirements and demands for the message exchange with an endpoint, and they allow the developer concentrating on the business logic.
- anonymousForCertificateSecurity. The client is anonymous but the service is authenticated using its X.509 certificate, and the client with the server´s public certificate can exchange messages with the service.
- kerberosSecurity. The client and the service are living within on rot more Windows Domains and Kerberos is the security infrastructure. Kerberos tickets are used for authentication and message protection. Kerberos are single sign-on, provides good performance, and supports impersonalization and delegation.
- mutualCertificate10Security and mutualCertificate11Security. The client and service exchange X.509 certificates that are used to secure the communication.
- usernameOverTransportSecurity. The client is identified using a username and password and then authenticated against some credentials storage such as Active Directory or SQL Server. The security protection is done on the transport layer.
- usernameForCertificateSecurity. The client is identified using a username and password and then authenticated against some credentials storage. The service is authenticated using an X.509 certificate.
You can apply one of these policies through the use of the PolicyAttribute for the service and the SetPolicy method for the generated client proxy. If you follow the declarative programming model, the policies are defined in a policy file which is an XML document consisting of a collection of named policies with the <policy> element, and within the <policy> element is the type of turnkey security assertion (anonymousForCertificateSecurity, kerberosSecurity, mutualCertificate10Security and mutualCertificate11Security, usernameOverTransportSecurity, usernameForCertificateSecurity) element which has several configurable attributes, such as whether to establish a secure session, the message protection, and so on. Depending of the turnkey security assertion, the file has a <serviceToken> element or <clientToken> element which describes where to get the security credentials, and finally the <protection> element indicates what parts of the messages are being signed and encrypted for the request, response and fault messages and the <requireActionHeader> indicates that all messages must contain the WS-Addressing header; otherwise, the message is rejected.
3. An example using WSE 3.0.
Let's illustrate all the concepts with an example. Our simple project is composed by a Web Service application providing a financial service (debit and credit operations) and a client consuming this service. Because these operations are vulnerable to attacks, we must use WS-Security related specifications for protecting the information integrity.
3.1 Developing the WSE 3.0 Service application.
From Visual Studio 2005, run the Add New Web Site wizard; select the ASP.NET Web Service template, as shown in Figure 1 below, and select a location to save the project structure. By default, the project has a Web Service component defined by the endpoint Service.asmx and the underlying code behind in App_Code special folder.
Figure 1.
Now we are going to add the business objects representing the architectural model of our solution.
The solution uses two entities which represent the inbound and outbound messages of the systems. Listing 1 and listing 2 shows the classes which represent the instances of MessageRequest and MessageResponse respectively. Those classes specify the properties, in our case AccountId, Amount, Status and Balance; and behavior of the entities as well as the schema of XML document for persistence of their instance.
[XmlRoot(Namespace = "http://www.financialserver.johnx.com/FinancialService/Schemas")]
public class MessageRequest
{
private int m_nAmount = 0;
private Guid m_uiAccountId = Guid.Empty;
public MessageRequest()
{ }
[XmlElement("Amount")]
public int Amount
{
get
{
return this.m_nAmount;
}
set
{
this.m_nAmount = value;
}
}
[XmlAttribute("Id")]
public Guid AccountId
{
get
{
return this.m_uiAccountId;
}
set
{
this.m_uiAccountId = value;
}
}
}
Listing 1.
[XmlRoot(Namespace = "http://www.financialserver.johnx.com/FinancialService/Schemas")]
public class MessageResponse
{
private int m_nStatus = 0;
private int m_nBalance = 0;
public MessageResponse()
{
}
[XmlElement("Status")]
public int Status
{
get
{
return this.m_nStatus;
}
set
{
this.m_nStatus = value;
}
}
[XmlElement("Balance")]
public int Balance
{
get
{
return this.m_nBalance;
}
set
{
this.m_nBalance = value;
}
}
}
Listing 2.
Other important business entity is represented by the Account class which classifies uniquely all the accounts inside a Finance and Account Information System, see Listing 3.
public class Account
{
private int m_nBalance = 0;
private Guid m_uiId = Guid.Empty;
public Account(Guid uiId)
{
this.m_uiId = uiId;
}
public int Balance
{
get
{
return this.m_nBalance;
}
set
{
this.m_nBalance = value;
}
}
public Guid Id
{
get
{
return this.m_uiId;
}
}
}
Listing 3.
And finally, the code definitions for the service object as shown in Listing 4.
[WebService(Namespace = "http://www.financialserver.johnx.com/FinancialService")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[Policy("KerberosTurnkeyServicePolicy")]
public class FinancialService : System.Web.Services.WebService
{
private Account prvGetAccount(Guid uiId)
{
Account objAccount = new Account(uiId);
return objAccount;
}
public FinancialService()
{}
[SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]
[WebMethod(MessageName = "Debit")]
public MessageResponse Debit(MessageRequest DebitRequestMessage)
{
MessageResponse objResponse = new MessageResponse();
Account objAccount = this.prvGetAccount(DebitRequestMessage.AccountId);
objAccount.Balance -= DebitRequestMessage.Amount;
objResponse.Balance = objAccount.Balance;
objResponse.Status = 0;
return objResponse;
}
[SoapDocumentMethod(ParameterStyle = SoapParameterStyle.Bare)]
[WebMethod(MessageName="Credit")]
public MessageResponse Credit(MessageRequest CreditRequestMessage)
{
MessageResponse objResponse = new MessageResponse();
Account objAccount = this.prvGetAccount(CreditRequestMessage.AccountId);
objAccount.Balance += CreditRequestMessage.Amount;
objResponse.Balance = objAccount.Balance;
objResponse.Status = 0;
return objResponse;
}
}
Listing 4.
Configuring the service for using the framework WSE 3.0 features.
We're going to configure the service project for using framework WSE 3.0.
-
In Visual Studio, right-click the application project, and then click WSE Settings 3.0 add-on.
-
Select both the Enable this project for Web Services Enhancements and the Enable Microsoft Web Services Enhancement SOAP Protocol Factory check boxes, which then ensure this project uses WSE when processing SOAP incoming and outgoing messages in ASP.NET runtime environment.
-
On the Policy tab, select the Enable Policy check box. A policy cache file with the default name "wse3policyCache.config" is added to the project.
-
On Edit Application Policy page, click Add, and then type a policy name for the new application policy, such as "KerberosTurnkeyServicePolicy".
-
Click OK to start the WSE Security Settings Wizard, and then click Next.
-
On the Authentication Settings page, it is provided a choice to secure a service or a client. Select the option for Secure a service application to configure the service.
-
It is also provided a choice of authentication methods. Select the option for Windows authentication, and then click Next. See figure 2.
Figure 2.
-
On the Kerberos Token Claims page, it is presented the configuration authorization based on the user name or roles contained in the KerberosToken. Select the Perform Authorization check box for performing authorization through the policy assertion, and then add users and roles as appropriate in the following format domain\principal. In our case, we are going to grant permission to the domain administrator as shown in Figure 3.
Figure 3.
-
On the Message Protection page, it is provided the configuration options for message protection. Select the option for Sign, Encrypt, Encrypt Signature, and select the Enable WS-Security 1.1 Extensions checkbox. WS-Security 1.1 Extensions allows using signature confirmation to correlate a response message from the service with the request message. Clear the Establish a Secure Session checkbox, it will be explained later why? See Figure 4.
Figure 4.
-
On the Create Security Settings page, it is possible to see what the wizard is going to generate for your application security policy, as shown in Figure 5.
Figure 5.
Configuring the client for using the framework WSE 3.0 features.
Now we're going to configure the client project for using the framework WSE 3.0 features using the following steps.
- In Visual Studio, right-click the application project, and then click WSE Settings 3.0 add-on Select the Enable this project for Web Services Enhancements check box, which then ensure this project uses WSE when processing SOAP incoming and outgoing messages.
- On the Policy tab, select the Enable Policy checkbox. A policy cache file with the default name "wse3policyCache.config" is added to the project.
- On Edit Application Policy panel, click Add, and then type a friendly policy name for the new application policy, such as "KerberosTurnkeyClientPolicy". The WSE Security Settings Wizard appears for generating a new policy.
- On the Authentication Settings page, it is provided a choice to secure a service or a client. Select the option for secure a client application to configure the client. It is also provided a choice of authentication methods. Select Windows choice, and then click Next, as showing in figure 6.
Figure 6.
- On the Kerberos Token page, it is provided the option to choose the service principal name (SPN) and to specify the impersonation level for the Kerberos Token. Set "http/[email protected]" for the SPN, select Impersonation for the impersonation level and click Next, as shown in figure 6. A service principal name (SPN) is the name by which a client uniquely identifies and authenticates an instance of a service. SPNs are used to request Kerberos tickets, and they are required for mutual authentication. The impersonation level allows specifying whether the authentication token identifies the client or impersonating the client.
Figure 7.
- On the Message Protection page, it is provided the configuration options for message protection. Select the option for Sign, Encrypt, Encrypt Signature, and set the Enable WS-Security 1.1 Extensions checkbox. WS-Security 1.1 Extensions allows using signature confirmation to correlate a response message from the service with the request message, see figure 8. Clear the Establish a Secure Session checkbox, it will be explained later why?
Figure 8.
- And finally, on the Create Security Settings page, it is possible to see what the wizard is going to generate for your application security policy, see figure 9.
Figure 9.
Now we're going to see why we cleared the Establish a Secure Session checkbox.
There are times when secure conversation and Kerberos can enter in conflicts. WSE 3.0 tries to acquire a Security Content Token (SCT) from the service to establish a secure conversation. The Request Security Context (RST) message sent from the client to acquire the SCT uses a KerberosToken to protect the message so that only the service can decrypt the message. By default, WSE 3.0 generates stateful SCT which means that the state of the SCT is carried with the SCT itself in the message. This state contains the server's KerberosToken inside of it. Since Kerberos Tokens can only ever be used once, using this stateful SCT doesn't work. This is because every time the client makes a request to the service, it protects the message with that SCT, which carries the state with it.
There are two options to figure this out:
- Don't establish a Secure Session.
- Establish a Secure Session and set statefulSecurityContextToken to false in the service configuration.
Watching the WS-Security message infoset.
We are going to see the first message of the sequence between the service and the client using WS-Security specification (the client requesting and sending security token and underlying security information to the Web Service). It is annotated in blue the HttpHeader and the HttpBody, and in red the encrypted data. You can see the XML elements referenced in the first part of this article such as wsa:Action, wsa:ReplyTo, wsse:Security, wsse:BinarySecurityToken. See listing 5.
HttpHeader
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.42)
Content-Type: text/xml; charset=utf-8
SOAPAction: http://www.financialserver.johnx.com/FinancialService/Credit
Host: john_developer.mydomain.com
Content-Length: 9565
Expect: 100-continue
Connection: Keep-Alive
HttpBody(XML Envelope)
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsa:Action wsu:Id="Id-3e198cb4-6afb-43eb-b04b-
070a54409251">http://www.financialserver.johnx.com/FinancialService/Credit
</wsa:Action>
<wsa:MessageID wsu:Id="Id-97847106-956a-4410-9f37-51f27b5c27d1">urn:uuid:7ae6647b-5a1c-43f8-8754-b3f99ee4a617
</wsa:MessageID>
<wsa:ReplyTo wsu:Id="Id-fe1d64eb-fc05-494d-9025-8683e429f0c6">
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To wsu:Id="Id-ecb265cf-25e9-467a-b9b5-acbb3ae0a362">
http://john_developer.mydomain/WSE30Server/Service.asmx</wsa:To>
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-dfdf0dc0-7329-4d04-8900-385be6d46829">
<wsu:Created>2006-07-07T16:10:25Z</wsu:Created>
<wsu:Expires>2006-07-07T16:15:25Z</wsu:Expires>
</wsu:Timestamp><wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#GSS_Kerberosv5_AP_REQ" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-se ]encrypted data -1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-f0c01367-8d46-4e0c-9400-30086cc12945">
</wsse:BinarySecurityToken><wssc:DerivedKeyToken wsu:Id="SecurityToken-1c4422f3-965f-441f-b028-4b546025726e" Algorithm="http://schemas.xmlsoap.org/ws/2005/02/sc/dk/p_sha1" xmlns:wssc="http://schemas.xmlsoap.org/ws/2005/02/sc"><wsse:SecurityTokenReference><wsse:Reference URI="#SecurityToken-f0c01367-8d46-4e0c-9400-30086cc12945" ValueType="http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#GSS_Kerberosv5_AP_REQ" /></wsse:SecurityTokenReference><wssc:Generation>0</wssc:Generation>
<wssc:Length>24
</wssc:Length><wssc:Label>WS-SecureConversationWS-SecureConversation</wssc:Label><wssc:Nonce>nY3yMdKluStQr8DArmIElA==</wssc:Nonce>
</wssc:DerivedKeyToken>
<wssc:DerivedKeyToken wsu:Id="SecurityToken-83455935-b1c8-44db-8989-c34e71cb2b69" Algorithm="http://schemas.xmlsoap.org/ws/2005/02/sc/dk/p_sha1" xmlns:wssc="http://schemas.xmlsoap.org/ws/2005/02/sc"><wsse:SecurityTokenReference><wsse:Reference URI="#SecurityToken-f0c01367-8d46-4e0c-9400-30086cc12945" ValueType="http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#GSS_Kerberosv5_AP_REQ" /></wsse:SecurityTokenReference><wssc:Generation>0</wssc:Generation>
<wssc:Length>32
</wssc:Length><wssc:Label>WS-SecureConversationWS-SecureConversation</wssc:Label><wssc:Nonce>CTqQC0+W7GhIYls2dKoVKA==</wssc:Nonce>
</wssc:DerivedKeyToken>
<xenc:ReferenceList xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:DataReference URI="#Enc-e46c2d9a-e063-4e7b-9262-a526af990759" /><xenc:DataReference URI="#Enc-80542942-7c3f-43be-b7f5-1b6e525d1c53" /></xenc:ReferenceList><xenc:EncryptedData Id="Enc-e46c2d9a-e063-4e7b-9262-a526af990759" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><wsse:SecurityTokenReference><wsse:Reference URI="#SecurityToken-83455935-b1c8-44db-8989-c34e71cb2b69" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" /></wsse:SecurityTokenReference></KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>Encrypted data</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></wsse:Security></soap:Header>
<soap:Body wsu:Id="Id-8df0b879-f80a-4705-8db3-a758e8c8c788"><xenc:EncryptedData Id="Enc-80542942-7c3f-43be-b7f5-1b6e525d1c53" Type="http://www.w3.org/2 ]encrypted data " xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" /><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><wsse:SecurityTokenReference><wsse:Reference URI="#SecurityToken-83455935-b1c8-44db-8989-c34e71cb2b69" ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/dk" /></wsse:SecurityTokenReference>
</KeyInfo><xenc:CipherData>
<xenc:CipherValue>encrypted data</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></soap:Body></soap:Envelope>
Listing 5.