Tuesday, November 25, 2008

Preventing DoS (Denial of Service) attacks on WCF services

WCF services are the most attractive target for hackers because even an unsophisticated hacker can bring down a server by repeatedly calling the WCF service. WCF uses mechanisms like Throttling and Quotas to prevent DoS attacks. Throttling allows you to "smooth" out the load on the server. WCF handles throttling through the ServiceThrottlingBehavior class. This represents a behavior that can be applied to a service.
The ServiceThrottlingBehaviour class contains three properties
  • MaxConcurrentCalls bounds the total number of simultaneous calls that we will process (default == 16). Each call corresponds to a Message received from the top of the server-side channel stack. If you set this high then you are saying that you have the resources to handle that many calls simultaneously. Increase this value if you want your service to be able to process a larger message load.
  • MaxConcurrentSessions bounds the total number of sessionful channels that we will accept (default == 10). When we hit this throttle then new channels will not be accepted/opened. Note that this throttle is effectively disabled for non-sessionful channels (such as default BasicHttpBinding).
  • MaxConcurrentInstances bounds the total number of instances created. This throttle provides added protection in the case that you have an instance lifetime that is not tied to a call or a session (in which case it would already be bounded by the other two throttles).
These properties can be applied either programmatically or by configuring the behavior in your web.config or app.config file.

<system.serviceModel>

<services>

<service behaviorConfiguration="TradeService.ExchangeService.ServiceBehavior" name="TradeService.ExchangeService.TradeService">

<endpoint binding="wsHttpBinding" contract="TradeService.ExchangeService.ITradeService"/>

service>

<service behaviorConfiguration="TradeServiceBehavior" name="TradeService">

<endpoint address="" binding="wsHttpBinding" contract="ITradeService">

<identity>

<dns value="localhost"/>

identity>

endpoint>

<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

service>

services>

<behaviors>

<serviceBehaviors>

<behavior name="TradeService.ExchangeService.ServiceBehavior">

<serviceMetadata httpGetEnabled="true"/>

<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="false" />

<serviceThrottling maxConcurrentCalls="16" maxConcurrentInstances="1000" maxConcurrentSessions="10"/>

behavior>

<behavior name="TradeServiceBehavior">

<serviceMetadata httpGetEnabled="true"/>

<serviceDebug includeExceptionDetailInFaults="false"/>

behavior>

serviceBehaviors>

behaviors>

system.serviceModel>


In the example given above I have set the maxConcurrentCalls to 16, maxConcurrentInstances to 1000 and maxConcurrenctSessions to 10.

Quotas can be used in situations where the client may force the server to allocate a significant amount of memory over what should be used. When a quota is exceeded a QuotaExceededException is thrown. Without Quotas a malicious message could attempt to access all available memory can create an OutOfMemoryException, or access all available stacks to cause a StackOverflowException.
By setting the maxRecievedMessageSize on the binding you can mitigate DoS attacks. This setting restricts the maximum messages size so that a client can’t send messages that are too large and flood the system.

<bindings>

<wsHttpBinding>

<binding name="WSHttpBinding_TradeService" closeTimeout="00:01:00"

openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"

maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"

allowCookies="false">

<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

maxBytesPerRead="4096" maxNameTableCharCount="16384" />

<reliableSession ordered="true" inactivityTimeout="00:10:00"

enabled="false" />

<security mode="Message">

<transport clientCredentialType="Windows" proxyCredentialType="None"

realm="" />

<message clientCredentialType="Windows" negotiateServiceCredential="true"

algorithmSuite="Default" establishSecurityContext="true" />

security>

binding>

wsHttpBinding>

bindings>

No comments: