Message Validation

patterns & practices Developer Center

If you make unfounded assumptions about the type, length, format, or range of input, your application is unlikely to be robust. Input validation can become a security issue if an attacker discovers that you have made unfounded assumptions. The attacker can then supply carefully crafted input that compromises your application. Misplaced trust of user input is one of the most common and serious vulnerabilities in WCF applications.

Consider these guidelines to help avoid input data validation vulnerabilities:

  • If you need to validate parameters, use parameter inspectors.
  • Use schemas with message inspectors to validate messages.
  • Use regular expressions in schemas to validate format, range, or length.
  • Implement the AfterReceiveRequest method to validate inbound messages on the service.
  • Implement the BeforeSendReply method to validate outbound messages on the service.
  • Implement the AfterReceiveReply method to validate inbound messages on the client.
  • Implement the BeforeSendRequest method to validate outbound messages on the client.
  • Validate operation parameters for length, range, format, and type.
  • Do not rely on client-side validation.
  • Avoid user-supplied file name and path input.
  • Do not echo untrusted input.

Each of these guidelines is described in the following sections.

If you need to validate parameters, use parameter inspectors

If you need to validate parameters passed to operations, use parameter inspectors. Parameter inspectors are extensibility points that are plugged into the WCF behaviors that allow the inspecting of parameter values during message exchange. Parameter validation can happen on both the client and the service.

You should validate all parameters exposed in WCF service operations to protect the service from attack by a malicious client. Conversely, you should also validate all return values received by the client to protect the client from attack by a malicious service.

You can use parameter inspectors to inspect simple types or types with fewer fields, passed to operations that will not result in complex validation logic. If you need to validate complex types, or data/message contracts with several fields to be validated, use schema validation with message inspectors.

Additional Resources

Use schemas with message inspectors to validate messages

If you need to validate parameters, message contracts, or data contracts passed to operations, use schema validation with message inspectors. Message inspectors are extensibility points that are plugged into the WCF behaviors that allow the inspecting of messages during message exchange. Schema validation can happen on both the client and the service. Use schema validation with message inspectors to validate messages without needing to write validation code. Additionally, schema validation will allow validating of complex types, message contracts, and data contracts, passed to operations that will not result in complex validation logic.

Additional Resources

Use regular expressions in schemas to validate format, range, or length

Consider using regular expressions in schemas to validate format, range, or length. This allows you to use complex validation logic without the need for implementing the complex validation code. Using regular expressions also allows you to decouple the validation logic from the business logic. Schema validation provides a way to create validation for data types using XML rules, for validity checks with regard to format, length, and type. Schema validation also supports the use of regular expressions. Without regular expressions, complex validation code would be required.

The following example schema exemplifies the validation of integer with values between 1 and 5, the string of length 5, and a Social Security number and ZIP code with valid formats:

<xs:schema elementFormDefault="qualified" targetNamespace="http://Microsoft.PatternPractices.WCFGuide" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://Microsoft.PatternPractices.WCFGuide">
  <xs:element name="GetData">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" name="CustomerInfo" nillable="false" type="tns:CustomerData" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:complexType name="CustomerData">
    <xs:sequence>
      <xs:element name="CustomerID" type="tns:CustIDLimitor">
      </xs:element>
      <xs:element name="text" type="tns:CustomerN">
      </xs:element>
      <xs:element name="ssn" type="tns:SSN">
      </xs:element>
      <xs:element name="zip" type="tns:us-zipcode">
      </xs:element>
    </xs:sequence>
  </xs:complexType>
  <xs:simpleType name="SSN">
    <xs:restriction base="xs:token">
      <xs:pattern value="[0-9]{3}-[0-9]{2}-[0-9]{4}"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="us-zipcode">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9]{5}(-[0-9]{4})?"/>
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="CustomerN">
    <xs:restriction base="xs:string">
      <xs:minLength value="1" />
      <xs:maxLength value="5" />
    </xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="CustIDLimitor">
    <xs:restriction base="xs:int">
      <xs:minInclusive value="1" />
      <xs:maxInclusive value="5" />
    </xs:restriction>
  </xs:simpleType>
  <xs:element name="GetDataResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="1" name="GetDataResult" nillable="false" type="tns:CustomerData" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

Implement the AfterReceiveRequest method to validate inbound messages on the service

If you need to perform validation of inbound messages on your service, implement the AfterReceiveRequest method of the message inspector's IDispatchMessageInspector interface. This will validate the message after the client request has arrived and before service operation invocation and deserialization.

Inbound message validation will be required if you want to validate the message when it is received by the client and before invoking the operations in the service. Input data validation represents one line of defense in the protection of your WCF application. Validate all parameters exposed in WCF service operations to protect the service from attack by a malicious client.

The following example shows how to implement the AfterReceiveRequest method:

object IDispatchMessageInspector.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
    try
    {
        validateMessage(ref request);
    }      
    catch (FaultException e)
    {
        throw new FaultException<string>(e.Message);
    }
    return null;

}

Additional Resources

Implement the BeforeSendReply method to validate outbound messages on the service

If you need to perform validation of outbound messages on your service, implement the BeforeSendReply method of the message inspector's IDispatchMessageInspector interface. This will validate the message before sending the response to the client and the service operation invocation and serialization.

Outbound message validation is required if you want to validate the message before sending the response to the client, so that you can validate output parameters and message and data contracts.

The following code example shows how to implement the BeforeSendReply method:

void IDispatchMessageInspector.BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
    try
    {
        validateMessage(ref reply);                
    }
    catch (FaultException fault)
    {
        // if a validation error occurred, the message is replaced
        // with the validation fault.
        reply = Message.CreateMessage(reply.Version, new FaultException("validation error in reply message").CreateMessageFault() , reply.Headers.Action);
    }
}

Additional Resources

Implement the AfterReceiveReply method to validate inbound messages on the client

If you need to perform validation of inbound messages on the client, implement the AfterReceiveReply method of the message inspector's IClientMessageInspector interface. This will validate the message after the client response has arrived and before deserialization and the returning of the data to the client application.

The following example shows how to implement the AfterReceiveReply method:

void IClientMessageInspector.AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
 {
     validateMessage(ref reply);               
 }

Additional Resources

Implement the BeforeSendRequest method to validate outbound messages on the client

If you need to perform validation of outbound messages on the client, implement the BeforeSendRequest method of the message inspector's IClientMessageInspector interface. This will validate the message before sending the request to the service and after serialization.

Outbound message validation is required if you want to validate the message before sending the request to the service, so that you can validate input parameters and message and data contracts on the client.

The following example shows how to implement the BeforeSendRequest method:

object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
    validateMessage(ref request);
    return null;
}            

Additional Resources

Validate operation parameters for length, range, format, and type

Check for known good data and constrain input by validating it for type, length, format, and range. Do not trust any input. An attacker passing malicious input can attempt SQL injection, cross-site scripting, and other injection attacks that aim to exploit your application's vulnerabilities.

If the client application that consumes your WCF service is a Web-based application, use the ASP.NET validator controls, such as the RegularExpressionValidator, RangeValidator, and CustomValidator, to validate and constrain input. Check all numeric fields for type and range. If you are not using server controls, you can use regular expressions and the Regex class. You can validate numeric ranges by converting the input value to an integer or double and then performing a range check.

Do not rely on client-side validation

Do not rely on client-side validation because it can be easily bypassed. While you may have control over the source code for the clients that call your service, clients can be reverse-engineered or built from scratch to attack your service. Use client-side validation to reduce round-trips to the server and to improve the user experience, but always use validation in the service itself to perform security checks.

Avoid user-supplied file name and path input

Wherever possible, avoid writing code that accepts user-supplied file or path input. Failure to do this can result in attackers coercing your application into accessing arbitrary files and resources. If your application must accept input file names, file paths, or URL paths, validate that the path is in the correct format and that it points to a valid location within the context of your application.

File names

Ensure that file paths only refer to files within your application's virtual directory hierarchy if that is appropriate. When checking file names, obtain the full name of the file by using the System.IO.Path.GetFullPath method.

File paths

If you use MapPath to map a supplied virtual path to a physical path on the server, use the overloaded Request.MapPath method that accepts a bool parameter so that you can prevent cross-application mapping. The following code example shows this technique:

try
{ 
 string mappedPath = Request.MapPath( inputPath.Text, 
                                      Request.ApplicationPath, false);
}
catch (HttpException)
{
 // Cross-application mapping attempted 
}

Note

The final false parameter in Request.MapPath() prevents cross-application mapping. This means that a user cannot successfully supply a path that contains ".." to traverse outside of your application's virtual directory hierarchy.

Do not echo untrusted input

Do not echo input back to the user without first validating and/or encoding the data. Echoing input directly back to the user can make client applications that rely on your service susceptible to malicious input attacks, such as cross-site scripting.