Building Secure Applications with WCF RIA Services
[WCF RIA Services Version 1 Service Pack 2 is compatible with either .NET framework 4 or .NET Framework 4.5, and with either Silverlight 4 or Silverlight 5.]
This topic provides guidance for ensuring secure usage of a domain service. When you expose a domain service by applying the EnableClientAccessAttribute attribute, the domain service is available to everyone on the network where it is exposed. You cannot assume that your client application is the only application that will access the domain service. This consideration is particularly important on a public network. However it is also important on a restricted network, such as a corporate network when sensitive data is being exposed.
The Add New Domain Service Class dialog box produces code that is intended to help you start working with a domain service. The code produced is not necessarily ready for deployment. You must review the code and modify it to meet the security requirements of your application. In particular, you must consider the operations you are making available to anyone on the network. The following checklist is a starting point for ensuring secure usage of a domain service.
To ensuring secure usage of a domain service, consider the following guidance.
Minimize the data and operations exposed by a domain service. This is the first line of defense against information disclosure and denial of service.
Expose only those entities that are needed by the client. This approach may require that you separate server logic and validation from client logic and validation, if it enables you to reduce the number exposed entities. For example, an expense report application that does not need the Employee entity on the client should not expose it through a domain service.
Shape entities to avoid exposing sensitive data. You can use the ExcludeAttribute attribute or Presentation Models to reduce the data that is available to a client. For example, if birth date and Social Security number are not required in an application, exclude them from the shape that is visible to the client.
Require query methods to take parameters that are needed in your application, instead of relying on data filtering capabilities in LINQ. For example, if expense reports are shown for a given employee, you should require an employee ID as a parameter in the query method and you should not provide a method that gets all expense reports. This approach minimizes the potential of data harvesting for all employees.
Create query methods that provide only the data needed for specific scenarios in your application. This approach means that you might provide multiple query methods that return portions of the data instead of a single query method that returns all of the data. For example, if products are shown by category or supplier, you can provide two methods that accept category or supplier information, instead of a single method that returns all of the products.
Filter data to provide only the data normally required for your application. For example, you might have a query method that returns only orders that were fulfilled in the past year.
Restrict the number of results that can be returned from a query to minimize accidental or deliberate overloading of the server. You use the ResultLimit property on the QueryAttribute to throttle the numbers of results that can be returned. For example, if a large number of products can be returned, enforce paging on the client by throttling the results to 20. Also, consider using the OutputCacheAttribute attribute for output caching to reduce the load on the middle tier and database.
Minimize the number of operations for each exposed entity. For example, if an order application only needs to add or modify orders, you should expose query, insert, and update operations on the orders entity, but not delete operations. In addition, you should expose only query operations for the products entity but not any data modification operations.
Whenever possible, use named update methods that restrict which members can be updated.
Restrict data and operation access to authenticated users and users in specific roles.
Avoid anonymous access whenever possible by using the RequiresAuthenticationAttribute attribute. When you must allow anonymous access, limit it to the smallest set of domain services and the smallest subset of operations within those domain services.
Add the operation-specific RequiresRoleAttribute attribute whenever possible. Consider each operation separately in a domain service. For example, all users may need to query the products entity, but only users in the administrator role need to update it.
Consider using the AuthorizationContext property to provide a customized authorization model.
Treat any data sent by a client as suspicious. A malicious client (even one that is authenticated and authorized) can provide tampered values for current and original values in a change set. Your application logic should not assume that these values are trustworthy. Instead, consider potential threats from tampered original values.
Use the https protocol for Forms Authentication. Sending passwords in clear text is a significant vulnerability, but it can be mitigated by using https.
Expose the minimum number of endpoints. By default, RIA Services creates a binary endpoint for a domain service. Add additional endpoints only if you have clients that specifically need the endpoints. Disable any endpoints that are not in use.