Using an HTTP Module to assist in adjusting the value of aspnet:MaxHttpCollectionKeys imposed by MS11-100

Internet applications using ASP.Net recently had an update (MS11-100) pushed out of band back in December that set a limit of 1000 items to be accepted by a web form.  While this is not the only limit imposed, it is the one that some applications are hitting.  If you exceed this value, an exception is thrown that looks like the one below:

System.Web.HttpException:
The URL-encoded form data is not valid. ---> System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded()
   at System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding)
   at System.Web.HttpRequest.FillInFormCollection()
   --- End of inner exception stack trace ---
   at System.Web.HttpRequest.FillInFormCollection()
   at System.Web.HttpRequest.get_Form()

The key here is ThrowIfMaxHttpCollectionKeysExceeded.  If that is in your stack trace, you know that you have exceeded the value the patch imposes.

To keep this exception from being thrown, you need to change the value of aspnet:MaxHttpCollectionKeys in the web.config of your application to a value that is as high as the highest allowed count of keys in your hash table. 

To help you figure out what value you should use in production, I have created a HTTP Module that counts the number of keys in that collection for each request and stores the high water mark in the event log once the module is unloaded.  I have included a sample that shows how this works.

For you to test this in your application, you need to build the MS11-1000Helper.DLL and place it in your web application’s Bin directory.  Once you have done this, you need to add the following to your web.config file to enable the HTTP Module:

<system.web>

    <httpModules>

      <add type="MS11_100_Helper.CounterModule, MS11-100-Helper" name="CounterModule" />

    </httpModules>

</system.web>

 

Additionally, you need to add the following to your appSettings:

<appSettings>

    <!--

      This is a super high number to use as a starting point in TESTING your application.

      You should never have a number like this in your PRODUCTION web.confg.

      Instead, you should use this HTTP module (MS11-100-Helper.dll) to help you determine

      the appropriate number to use for your setting in PRODUCTION.

    -->

    <add key="aspnet:MaxHttpCollectionKeys" value="9999" />

</appSettings>

 

Then you should TEST your application.  If you are dynamically generating Forms items in your application, you need to test with the highest amount of generated UI as you expect to ever see while your application is being run. 

After you have tested the above scenario, you need to close the browser and terminate the web server (stop the development server or issue an IISRESET).  Once you have done this, the high water mark should be written to the event log “Applications and Services Logs/CounterSourceLog” and you should have an Information entry that looks like this:

Largest Value Seen = X

Where X is some number. 

You can then use this number to help you set the value of aspnet:MaxHttpCollectionKeys in production. 

I would personally set the number to be a little higher than the value here, but that depends on the application.  If you don’t have a lot of dynamically generated forms controls, then the number is probably pretty close to what you can use for your deployed application.  You might want to add just a few more to the value just in case you have a last minute tweak that puts you over the limit.

If you have pages that can dynamically generate a ton of controls without limit (indicating a bad design), then this isn't going to help you much.

Just be sure to remove the module and 9999 limit from your production code!!!  

There are a couple of additional caveats with this as far as being the end all to this issue. 

First, realize that MS11-100 is a workaround to help limit a DOS attack.  The final fix will be to randomize the hash tables used in the ASP.Net will be in a change that comes later.  Once that change is available, this workaround may not be needed.

Second, this helper only counts the keys in the Form collection.  If you are running into an issue where you are seeing an exception thrown for Json, then this code will not help you.

Third, if the high water mark is less than 1000, I wouldn't recommend changing the default app setting of aspnet:MMaxHttpCollectionKeys.  A DOS attacker will probably be hitting numbers much higher than this to cause the issue to occur, which is why we choose the number to begin with.

Fourth, anytime you make an application change, you should reuse this tool in TEST to help you figure out the value of the setting in production.

Special thanks to Wyn Lewis-Bevan for the idea on developing this helper!

MS11-100-Helper.zip