Security Best Practices: Web Services

From WS-Attacks
Jump to: navigation, search

Introduction

Web services are often used for important tasks operating on crucial data. Many web services need to be accessible from the Internet for their intended purpose. Therefore, they are interesting targets for criminals trying to attack them with different techniques.

In order to defend the data processed by web services and the availability of web services themselves security features need to be applied. The WS-Security standard defines such features. Most of the common web service frameworks support the “WS-Security” standard right away, for example Apache CXF.

In the following, a check list with configuration best practices that will help to develop and configure secure web services will be presented. The configuration in general aims to achieve the following four main goals:

  1. Integrity and Authenticity: The "WS-Security" standard allows to use signatures as defined in the XML Signature standard to secure certain parts of the SOAP messages. The signatures make sure that these parts have not been manipulated during transmission (integrity) and allow the author of the message to authenticate himself to the recipient (authentication).
  2. Confidentiality: In addition to signatures the "WS-Security" standard allows the application of XML Encryption to encrypt certain parts of the messages. This makes sure that the information included in these parts can only be read by the intended recipient of the message and remains secret to attackers and other possible parties.
  3. Freshness: Lastly the "WS-Security" standard defines the use of timestamps and nonces to make sure that messages are only valid for a short period of time and cannot be used for replay attacks.
  4. Availability: Attackers might try to influence the availability of web services in a negative way by executing Denial-of-Service (short: DoS) attacks. The different DoS techniques need to be prevented in order to ensure that the web service is available to clients and responds to their requests in reasonable time.

However, all goals might not be relevant for every web services. For example, confidentiality (and authenticity) might not be relevant for a web service simply providing weather information to clients.

The decision which goals are relevant and which security features should be enabled in order to achieve them needs to be made individually for every web service.

An example that shows how to enable the configuration on web services built with the CXF web service framework can be found here: Security Best Practices: Apache CXF

Secure web services check list

The following check list helps to make sure that the relevant security features are enabled.
A PDF version of the plain checklist without explanations and details (for printing etc.) can be downloaded here.

(Clicking on the name of a feature will forward to a section with detailed information and recommendations about it.)

Goal Mechanism/Feature Fulfilled/ Complied/ Satisfied Not fulfilled Not relevant
Integrity + Authentication Signature
Confidentiality Encryption
Freshness Timestamps and nonces
Availability DoS prevention
Miscellaneous Miscellaneous

Signature

Signatures can be used to ensure the integrity and authenticity of a (part of a) message. In general, all web services should use signatures to secure the exchanged messages against manipulation and impersonation by attackers except the exchanged data is neither used for crucial tasks nor sensitive itself (e.g. weather data provided by a web service that is not used to plan or executed further actions). As stated above the "WS-Security" standard uses the "XML Signature" standard to allow signatures for SOAP-based web services. Due to this it is possible to sign parts of messages as well as whole messages.

Usually the Body-part of both requests and responses is secured by a signature. It is important to note that the decision which parts of a message should be secure by a signature depends strongly on the specific web service and the information and structure of the messages. All parts of a message that include important information should be secured by a signature. For example, if the web service uses WS-Addressing the "WS-Addressing"-elements in the Header-part of the messages should be secured by a signature as well (see Miscellaneous for additional recommendations regarding "WS-Addressing"). Also, if timestamps or nonces are enabled or parts of the messages are encrypted they should be signed.

In addition to the decision which parts should be signed the choice of the signature and the digest algorithms is an important part of a secure configuration: Instead of SHA1 newer algorithms from the SHA2 ("SHA-256", "SHA-384" or "SHA-512") or SHA3 ("SHA3-256", "SHA3-384" or "SHA3-512") family should be used as the digest algorithm, because "SHA1" is broken [1]. All mentioned algorithms are recommended by the german "Bundesamt für Sicherheit in der Informationstechnik" (short: BSI) in the document BSI TR-02102 Kryptographische Verfahren: Empfehlungen und Schlüssellängen (pages 38-39). The recommended signature algorithms are RSA with a key size of (at least) 2048 bit (see Key generation for more details) or the elliptic-curve version of DSA (called "ECDSA") with a key size of (at least) 250 bit. Again, this follows the recommendations of the BSI (RSA: pages 42-43, ECDSA: page 44).

Even if a signature is applied attackers can try to bypass the protection by applying [ XML signature wrapping] (short: XSW) attacks. XSW attacks allow attackers to manipulate certain parts of the request unnoticed although the integrity of these parts is secured by a signature. The main idea of XSW attacks is to copy the signed parts to a different location and manipulate the original elements. Some web services will accept the tampered request because the signature verification was successful and execute the function call in the Body of the request although the executed parts were not signed.

It is recommended to make sure that the web service only executes the signed parts of a message if a signature is present.

When signatures are used to secure a web service, all clients and the web service itself need a public-/private key pair. The generation of such key pairs is described in section Key generation. The web service needs to know the public key (resp. the certificate) of the client to verify the signature if he receives a request with signed elements. The "WS-Security" standard defines multiple possibilities to include a reference or the needed certificate itself in the Header of SOAP messages.

It is recommended to only accept certificates that are already present in the keystore of the web service and referenced by their ID in the request. If certificates are sent in the Header of the requests themselves (for example in "BinarySecurityToken" elements) they must be validated locally whether they are trustworthy. It is recommended to exchange the certificates of all clients and the web service prior to their use and both store the clients' certificates in the web service's keystore and the web service’s certificate in the keystores of all clients.

Configuration Recommendation Fulfilled Not fulfilled Achieved with
Signed parts Body and other crucial parts (e.g. timestamps, nonces, encrypted parts, WS-A headers ...)
Signature algorithm RSA (≥ 2048 bit keys) or ECDSA (≥ 250 bit keys)
Digest algorithm Algorithm from SHA2 or SHA3 family, e.g. SHA-256
Prevent XSW attacks Execute signed parts of the message only
Certificate trust Reference certificates by their ID and validate locally whether they are trustworthy

In addition to the presented recommendations development best practices from the W3C can be found here: XML Signature Best Practices

Encryption

Encryption is used to reach the goal of confidentiality. It ensures that the contents of the messages can only be read by the indented recipient and remains unknown for potential attackers as well as all other possible parties during transmission of the messages. As a general guideline, every information that is not publicly known or available from other public sources should be encrypted. It is common to encrypt the contents of the whole Body-element and send the Header-element in plaintext because the Header usually only contains non-sensitive meta-information about the message itself. However, the specific choice of parts of requests and responses which should be encrypted depends strongly on the web service and needs to be taken individually for every web service.

Again, the "WS-Security" standard makes use of another standard to allow the encryption of certain parts of the requests/responses – the "XML Encryption" standard. The "XML Encryption" standard defines multiple different algorithms for the encryption, but again the choice of the algorithm is an important part of a secure configuration because only a few algorithms are good in the terms of security. To increase the performance, it is highly recommended to use a hybrid cryptosystem which contains of an asymmetric algorithm to establish a symmetric key and a symmetric algorithm to encrypt the communication with the established key. As the asymmetric algorithm "RSA" in the "RSA-OAEP" variant should be used, again with a key size of (at least) 2048 bit. The "RSA-PKCSv1.5" variant should not be used because it is vulnerable to certain attacks. For the symmetric encryption of the communication the recommended key length is (at least) 128 bit; the recommended algorithm is AES (BSI, page 22). "AES" exists in three different variants with different key lengths: "AES-128", "AES-192" and "AES-256". "AES-128" is sufficient for most purposes.

Web service frameworks like "Apache CXF" support the use of "AES-256" as well, but due to a limitation of Java both the web service and all clients need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files to be able to use "AES-256". This limitation needs to be considered if the use of "AES-256" is intended.

In addition to multiple variants of "AES" regarding the key length there are different modes of operation. These modes are needed to be able to encrypt data of all possible sizes. The most common (and one of the easiest) mode is the so-called "CBC"-mode. Although this mode has been the victim of successful attacks in the past, better modes – like the "GCM"-mode – are still not very common and not widely supported. Sadly, most web services frameworks do not support the "GCM"-mode. Therefore the "CBC"-mode needs to be used in most cases. Luckily the weaknesses of the "CBC"-mode can be mitigated heavily when combining encryption with a signature: By securing the encrypted elements against tampering adaptive "choosen-ciphertext attacks" (short: CCA) are prevented. Note: Some web service frameworks select the order of applying encryption and signature themselves in default configuration. However, the order is not irrelevant. It is important to follow the "Encrypt-then-Sign" order, because otherwise the countermeasure won't be effective! Additional information and details about CCA and countermeasures in terms of web services can be found here.

Configuration Recommendation Fulfilled Not fulfilled Achieved with
Encrypted parts Parts containing non-public information (e.g. Body)
Encryption algorithms Asymmetric key establishment RSA-OEAP (≥ 2048 bit keys)
Symmetric data encryption AES-128 or AES-256 in GCM-mode if available, CBC-mode in combination with a signature otherwise
Combine encryption with a signature Signed parts All encrypted parts
Order to apply Encrypt-then-Sign

Instead of an "RSA" based key establishment algorithm it is also possible to use Elliptic Curve Cryptography (short: ECC). However, not all web service frameworks and clients support ECC.

To be able to enable encryption for a web service public-/private-key pairs for the service and all clients are needed. The generation of such key pairs is described in section Key generation.

Timestamps and nonces

Timestamps are used to restrict the time a message is valid and nonces are used to enable recipients to recognize messages they receive more than once. Both help to prevent replay attacks and the use of manipulated versions of older messages for other attacks.

Generally, timestamps and nonces increase the security of all web services, but if they are not secured by a signature they can be manipulated – respectively updated – easily. Therefore, it is recommended to never use unsigned timestamps or nonces. In order to recognize that a received message has been sent multiple times the web service needs to store the nonces in a cache and check if the nonce is already present in this cache when a new message is received.

It is recommended to use signed timestamps in both requests and responses in combination with singed nonces for all web services.

Configuration Recommendation Fulfilled Not fulfilled Achieved with
Timestamps Enable for all messages
Nonces Enable for all messages
Secure timestamps and nonces against tampering Sign timestamps and nonces

DoS prevention

One of the main goals for attackers - beside the unauthorized access to functions of the web service or information processed by the web service - is to make the web service unavailable (or at least more time-consuming) for legitimate users. So-called "Denial-of-Service" (short: DoS) attacks can be based on many different techniques. Due to the high number of known (and probably unknown) techniques for DoS attacks it is hardly possible to secure a web service completely. However, a secure configuration prevents a lot of the DoS attack techniques.

Firstly, every message the web service processes should be validated against XML Schema files. These files define the allowed structure of the XML messages. The validation should include the SOAP and "WS-Security" schema at least. To increase the protection against DoS attacks based on XML an own schema file for the specific web service should be written with the structure of the requests in mind. As a guideline, the schema should be as "tight" as possible to give attackers as little places/space to inject DoS payload as possible. XML schema validation has another positive effect in the context of security: By validating requests against a schema not only the places for DoS payload are reduced but also the places attackers can place payload for XML Signature Wrapping (short: XSW) attacks. However, XML schema validation is not sufficient to fully prevent XSW attacks. In the Signature section there is more information about another possible way to prevent XSW attacks.

The second XML based DoS technique that can be mitigated by a secure configuration uses "Document Type Definitions" (short: DTDs) to define "XML Entities". These entities can be used to write long or complicated data multiple times within one XML document. Attackers can use multiple entities which reference each other recursively in the request to exhaust the memory of the web service. This creates a rather small request but huge memory consumption for the web service when the message is parsed. Using another technique an attacker could create two entities referencing each other resulting in an infinite loop during the parsing process. The third "XML Entity" based DoS attack technique uses entities that reference huge external resources from anywhere on the internet. When the web service starts to parse the request, he will try to load the external resource. This will result in huge memory consumption and slow the web service down eventually making it completely unavailable for other clients for a period of time. Alternatively to referencing a huge external file for a DoS attack, an attacker could also reference a local file stored on the web service itself or on another server that is not directly accessible to the attacker. The web service will eventually load the referenced file and paste its content into the response resulting in the leak of a local/internal file.

The recommended mitigation to all DoS attacks based on "DTDs" resp. "XML Entities" (and the possible file leak based on external "XML entities") is simply disabling the support of "DTDs"/"XML Entities" completely. Because "DTDs" and "XML Entities" are relatively uncommon nowadays it is recommended to disable them for all web services generally.

Another easy DoS attack technique is simply sending a huge number of messages or one huge message to the web service. To defend against such attacks the web service must throttle the amount of data it accepts in a certain period of time and the size a single message is allowed to have. It is recommended to enable a threshold for the size of single messages as well as a maximum of messages the web service will accept per second/minute. If the threshold or the maximum is exceeded the web service should reject the rest of the message and further received messages.

Configuration Recommendation Fulfilled Not fulfilled Achieved with
XML Schema Validation Validate messages against SOAP, "WS-Security" and own schema
DTDs/XML Entities Disable support completely
Data throttling Enable a maximum message size and a maximum of messages accepted in a time period

Miscellaneous

Configuration Recommendation Fulfilled Not fulfilled Achieved with
SOAPAction parameter Disable or implement check if parameter and function call in Body match
WS-Addressing Disable or enforce strict whitelist

SOAPAction parameter

The SOAPAction parameter is present in the HTTP header of the request and usually represents the function call in the SOAP Body of the request. This parameter is often used by firewalls to determine whether a request from a certain source should be accepted (and forwarded to the web service) or not. The advantage of the parameter is that firewalls don’t need to parse the whole XML document for this task saving them a lot of time. Although the parameter is intended for firewalls etc. web services need to consider it as well. Some web services ignore this parameter and simply execute the function which is called in the Body of the request. This allows attackers to simply change the parameter to a function the firewall allows and still make the web service execute a disallowed function. There are also web services that simply execute the function referenced by the SOAPAction parameter without checking the actual function call in the Body of the request. This enables attackers to change the executed function even if they cannot tamper the Body of the request because it is secured by a signature, for example.

It is highly recommended to disable the SOAPAction parameter if it is not needed or to make sure that the web service verifies that the parameter references the same function that is called in the Body of the request. If this is not the case the web service should not execute any function and reject the request.

WS-Addressing

The WS-Addressing standard allows the addition of addressing information to the Header of SOAP messages with elements like "To", "ReplyTo" and "FaultTo". Attackers can abuse these elements to reach web services or other servers that are not directly accessible to them.

It is recommended to only use "WS-Addressing" if it absolutely necessary. Otherwise "WS-Addressing" support should be disabled completely. If the usage of "WS-Addressing" is indispensable a strict whitelist policy of allowed addresses should be enforced.

Note: A blacklist approach is not sufficient because it is impossible to create a complete list of forbidden addresses.

Key generation

For the use of both encryption and signatures the web service and all its clients need a public-/private-key pair or a certificate, respectively. The key generation process can differ depending on the specific web service and its (technical) environment. It is possible that a working public key infrastructure (short: PKI) is already present in the company, for example. If this is the case the certificates should be obtained from this PKI. Otherwise it is possible to obtain certificates from public certificate authorities (short: CA) or to create the key pairs with the Java keytool (ships with Java development kit (JDK)) and self-sign them. It is not always necessary to obtain certificates from public certificate authorities. However, it is important to make sure that self-signed certificates are distributed through secure and authenticated channels only. As stated in the "Encryption" and "Signature" sections the recommended asymmetric algorithms are based on "RSA" and the recommended key length is (at least) 2048 bit. Therefore, the needed key pairs must be "RSA" keys with a length of (at least) 2048 bit. The last important parameter for the key generation is the validity of the generated keys. It is recommended to change the keys once a year if the environment the web service is used in allows frequent key changes for clients and the web service itself.

In the following the keytool will be used to create a test key pair for the web service and a test key pair for one client. The key pairs are stored in Java keystores. Afterwards the public keys will be exported and imported in the opposite keystore.

To make sure that the keys are also appropriate for the future a key length of 3072 bit is used in this example.

  1. Create a public-/private-key pair for the web service:
    Execute the following commands in a console:
  2. keytool -genkey -alias service -dname "cn=service" -keystore service_keystore.jks -storepass *servicekeystorepassword* -keypass *servicekeypassword* -keyalg RSA -validity 365 -keysize 3072
    keytool -selfcert -alias service -keystore service_keystore.jks -storepass *servicekeystorepassword* -keypass *servicekeypassword*
  3. Create a public-/private-key pair for a client:
    Execute the following commands in a console:
  4. keytool -genkey -alias client1 -dname "cn= client1 " -keystore client1_keystore.jks -storepass *client1keystorepassword* -keypass *client1keypassword* -keyalg RSA -validity 365 -keysize 3072
    keytool -selfcert -alias client1 -keystore client1_keystore.jks -storepass *client1keystorepassword* -keypass *client1keypassword*
  5. Export the public-keys and import them in the opposite keystore:
    Execute the following commands in a console:
  6. keytool -export -alias service -file service.pubkey -keystore service_keystore.jks -storepass *servicekeystorepassword*
    keytool -export -alias client1 -file client1.pubkey -keystore client1_keystore.jks -storepass *client1keystorepassword*
    keytool -import -alias client1 -file client1.pubkey -keystore service_keystore.jks -storepass *servicekeystorepassword*
         Trust this certificate? [no]:  yes 
    keytool -import -alias service -file service.pubkey -keystore client1_keystore.jks -storepass *client1keystorepassword*
         Trust this certificate? [no]:  yes

Note: The bold parts of the commands are only chosen for this example and need to be changed when creating keys for an actual web service in productive use; especially the passwords of the keystores and the private-keys need to be chosen carefully! (*servicekeystorepassword*, *client1keystorepassword*, *servicekeypassword*, *client1keypassword*)

The important parameters mentioned above are used here: -keyalg RSA -validity 365 -keysize 3072

The last step to use the generated key pairs is to add the keystore created for the web service to it. It depends on the specific web service or web service framework used to build the web service how the .jks file is added. Usually a class is needed to access the private key from the keystore because it is secured with a password (*servicekeypassword* in this example).