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
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(
typeof(MyContract),
host.AddServiceEndpoint(
"IMyContract",
new
WSHttpBinding(),
"");
System.ServiceModel.Description.ServiceThrottlingBehavior
throttlingBehavior =
new
System.ServiceModel.Description.ServiceThrottlingBehavior();
throttlingBehavior.MaxConcurrentCalls = 16;
throttlingBehavior.MaxConcurrentInstances = Int32.MaxValue;
throttlingBehavior.MaxConcurrentSessions = 10;
host.Description.Behaviors.Add(throttlingBehavior);
host.Open();
or
through the app.config:
<system.serviceModel>
<services>
<service
name="IMyContract"
behaviorConfiguration="myContract">
<host>
<baseAddresses>
</baseAddresses>
</host>
<endpoint
name="wsHttp"
address=""
binding="wsHttpBinding"
contract="IMyContract">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="myContract">
<serviceMetadata httpGetEnabled="True" />
<serviceThrottling
maxConcurrentCalls="16"
maxConcurrentInstances="2147483647"
maxConcurrentSessions="10"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
There
are 3 properties supported on the ServiceThrottlingBehavior:
- 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.
- 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.
- 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.
Recommendations:
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).
Quotas
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.
<bindings>
<netTcpBinding>
<binding name="netTcp"
maxReceivedMessageSize="2147483647"
maxConnections="2147483647">
<readerQuotas
maxDepth="64"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="4096"
maxNameTableCharCount="16384"/>
</binding>
</netTcpBinding>
</bindings>
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:
- MaxDepth (default =
32) The maximum nested node depth.
- MaxStringContentLength
(default = 8192) The maximum string length allowed by the
reader. You may need to increase this value if you anticipate
potentially large messages.
- MaxArrayLength
(default = 16384) The maximum allowed array length. How many
items can be in a single array in the message.
- 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.
- 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@gmail.com
Regards
Sujeet Bhujbal
-----------------------------------------------------------
Personal
Website :- http://sujitbhujbal.wordpress.com/
Facebook
:- www.facebook.com/sujit.bhujbal
CodeProject:-http://www.codeproject.com/Members/Sujit-Bhujbal
Linkedin
:- http://in.linkedin.com/in/
sujitbhujbal
Stack-Exchange:
http://stackexchange.com/users/469811/sujit-bhujbal
Twitter
:- http://twitter.com/SujeetBhujbal
JavaTalks
:-http://www.javatalks.com/Blogger/sujit9923/
---------------------------------------------------------------