Wednesday 22 August 2012

Denial of service (DoS) attacks on your Wcf services

Denial of service (DoS) attacks on your Wcf services

What can you do to prevent denial of service (DoS) attacks on your Wcf services?  A DoS attack occurs when a flood of client requests come into a service and prevent requests from being made or slow down processing.  At the same time, you need to be careful not to requests and activity.


Throttling is one mechanism that can be used to help minimize the load from a DoS attack.  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.  Behaviors can be applied programmatically:

ServiceHost host = new ServiceHost(
    new WSHttpBinding(),
System.ServiceModel.Description.ServiceThrottlingBehavior throttlingBehavior =
    new System.ServiceModel.Description.ServiceThrottlingBehavior();
throttlingBehavior.MaxConcurrentCalls = 16;
throttlingBehavior.MaxConcurrentInstances = Int32.MaxValue;
throttlingBehavior.MaxConcurrentSessions = 10;

or through the app.config:

                    <add baseAddress="http://localhost:8080/MyContract"/>
            <behavior name="myContract">
                <serviceMetadata httpGetEnabled="True" />

There are 3 properties supported on the ServiceThrottlingBehavior:
  1. MaxConcurrentCalls (default = 16) [Per-message] The maximum number of messages that can actively be processed.  Each client channel can have one pending message that does not count against this total until the service begins to process it.  Increase this value if you want your service to be able to process a larger message load.
  2. MaxConcurrentInstances (default = Int32.Max)  The maximum number of InstanceContext objects in a service that can execute at one time.
    • What this setting translates into depends on the InstanceContextMode that is set on the ServiceBehaviorAttribute on the service.  If this is set to "PerSession", then this would represent the maximum number of sessions.  If this is set to "PerCall", then this is the maximum number of concurrent calls.  If this is set to "Single", then this value doesn’t really mean anything anymore.
    • When a message comes into the service and the maximum number of InstanceContext objects already exists, then the message goes into a wait pattern until an existing InstanceContext is closed.  This could cause a client to receive a timeout if no connection could be created in the allotted amount of time.
  3. MaxConcurrentSessions (default = 10) [Per-channel] The maximum number of sessions that a service can accept at one time.  This setting only affects "session" enabled channels, so a channel like BasicHttpBinding will not be affected.  Once this threshold is reached, no channels will not be accepted to the service.  Each listener object can have one pending channel session that does not count against this total until the service beings to process it.  Increase this value if you want to allow more than 10 concurrent sessions to be connected at any given time.
    • If you get exceptions like this, you may need to increase this value:
"The open operation did not complete within the allotted timeout of 00:00:59.9989999. The time allotted to this operation may have been a portion of a longer timeout."

"The socket transfer timed out after 00:00:59.9979998. You have exceeded the timeout set on your binding. The time allotted to this operation may have been a portion of a longer timeout."
You could set all the these values to Int32.Max.  This is probably a good think when you really want to perform some load testing of the server. (This is how I discovered the usefulness of these settings)  However it is important to understand what consequences there are to doing this.

If your InstanceContext is set to "PerCall" you should set maxConcurrentSessions and maxConcurrentCalls to the same value since each call is its own session.  You should target this value to be at least 25-30.  However you shouldn’t need to go higher than 64.
If your InstanceContext is set to "PerSession" you should set maxConcurrentCalls to be at least 25-30.  Your maxConcurrentSessions should be the number of users you want to have concurrently connected.
If your InstanceContext is set to "Single" you should use the same settings as "PerSession", but the maxConcurrentSessions will only apply if session support is active (this is set with the SessionMode attribute on the ServiceContractAttribute).

Another potential area that is vulnerable to a DoS attack is where the client may force the server to allocate a significant amount of memory over what should be used.   To help prevent this you can use Quotas.  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.  The best part of the QuotaExceededException is that the message causing it can just be discarded and the service can keep on running.  Without quotas the resulting exceptions could cause the service to terminate.
The most useful quota to work with to mitigate DoS attacks is the maxRecievedMessageSize on the binding itself.  This setting restricts the maximum messages size so that a client can’t send messages that are too large and flood the system.  The default value is 65536 bytes.
        <binding name="netTcp"

Other quotas exist on the ReaderQuotas property that can be used to restrict message complexity.  This can help mitigate excessive use of endpoint processing resources like CPU and memory. These are:
  1. MaxDepth (default = 32) The maximum nested node depth.
  2. MaxStringContentLength (default = 8192)  The maximum string length allowed by the reader.  You may need to increase this value if you anticipate potentially large messages.
  3. MaxArrayLength (default = 16384)  The maximum allowed array length.  How many items can be in a single array in the message.
  4. MaxBytesPerRead (default = 4096) The maximum allowed bytes returned for each read.  This is the number of bytes consumed by a single call from the reader to Read().  In practice this is used to limit the size of start tags, since a start tag must be completely buffered for the message to be processed.  This can be a common attack area.  It is recommended to keep this value at its default.
  5. MaxNameTableCharCount (default = 16384) The maximum number of characters in a table name.
Some bindings such as Net
TcpBinding offer a maxConnections property.  This setting on the client indicates the maximum number of connections to be pooled for subsequent reuse.  On the server, this setting is the maximum number of connections allowed to be pending dispatch.  The default is 10.

Happy Programming ! !
If you have any query mail me to     
Sujeet Bhujbal

No comments:

Post a Comment