Skip navigation.

Impressive Event Library from Yahoo!All recent postsOne Year Worth of Google Logos

Fighting View State Spam

This is a sequel to my earlier post, View State Lockdown. I keep seeing attempts to feed entire emails under the guise of view state. I don’t understand the point of such an attack. Those emails are posted in plain and clear while view state should be base64-encoded. It’s futile, yet annoying.

I set aside some time this week-end to write an HttpModule which would blacklist IPs where this attack comes from. I suspect those are anonymous proxies, zombies, etc. It’s noble and glorious to maintain an open proxy and thus be a beacon of “free e-speech,” but scumbags exploit them, and I have no moral remorse putting them on my blacklist.

As is often the case with spam, this is not so much a technical problem, but a social one. In fact, it took me 30 seconds to create a bare-bones functional HttpModule using my own tool. Everything else was deciding on one or more criteria for blacklisting IPs. I don’t expect Microsoft or hosting companies to solve this problem because they aren’t into… you know… social problems.

Is This an Attack?

The attack in question always trips the LoadPageStateFromPersistenceMedium method inside the Page class. However, a mere fact that view state is corrupted is not a good enough reason to blacklist the visiting IP.

In ASP.NET 1.1 there is no definitive way to tell that an exception has to do with processing view state. In 2.0 there’s a new exception class, ViewStateException, which is much better than nothing, but still not good enough to fight view state spam. Simply catching ViewStateException and blacklisting the visiting IP doesn’t work because here are numerous ways to corrupt view state, only one of them being malicious.

For example, you could add a dynamic control at the wrong place and at the wrong time (see the section on dynamically added controls in Scott Michell’s article Understanding ASP.NET View State). Or, you could be storing view state in the database—which I always advocate—and doing something wrong on its retrieval (I’ve done this many times). If you mistake this for an attack, you’ll blacklist your own site!

However, the email spam attack in question is special: they always feed plain text. If you bring it upon yourself with an improperly placed dynamic control, at least the view state is base64 encoded.

Finding Appropriate Criteria

I’ve gone through several iterations. In you peek inside Page.LoadPageStateFromPersistenceMedium() with Reflector, you see how this method builds an exception and prepends “Invalid_Viewstate” to it. This could be a convenient smoke test… with the exception of those cases when you store and load view state yourself (my article explains how).

Next, I wanted to run a regex to look for To: and Subject: fields which appear in 95% of spam emails. However, the remaining 5% contain only a single fake email and nothing else.

At this point I figured I could look for the ’@’ character which can’t appear in a base64 string. Can this potentially discriminate against someone with good, but sloppy intentions? Hardly. It takes a lot to screw up view state that bad.

Deployment

Feel free to copy and compile the source code. As provided, the code creates a file, ban_list.txt, in your app root and stores banned IPs there. I didn’t want to mess with XML config files and such—I wanted to keep it simple.

Every banned host is greeted with a 403 HTTP code. I do realize that many of you host sites elsewhere and therefore suggest that you create a blank ban_list.txt file beforehand to avoid permissioning mess. Not every ISP gives you a control panel to set permissions on file level.

Last but not least, remember to register the HttpModule in web.config. For example, I list it this way:

<httpModules>
   <add name="ViewStateSpamStopper" 
        type="AspNetResources.Web.ViewStateSpamStopper, 
              AspNetResources.Web"/>
</httpModules>

Conclusion

I don’t know if I’m missing some major issue with this simple solution. I’ve tried to take into account such edge cases as custom handling of view state persistence, misplaced dynamic controls, etc.

Please let me know if you have other suggestions and ideas.

Comments

Comment permalink 1 Alexey |
Is the code designed for 1.1 too? I've tried your code on my server and I'm still have "Invalid length for a Base-64 char array" in the log (I'm using ELMAH for that) and the ban_list.txt is empty (asp has rights)
Comment permalink 2 Alexey |
well, sorry, I found where my problem is
your code is great, thank you!

Emails and Notifications

Would you like to be notified when somebody responds to this post?  Would you like to have these comments emailed to you?

TrackBacks

Sorry, TrackBacks are not allowed.

Submit your comment

Please enter only text since all HTML tags except hyperlinks will be stripped. Hyperlinks will become live links. Any comments with flaming or offensive language will be deleted. Be courteous to other posters. Thank you.

Your name (required):
Your email (optional):
Your site's URL (optional):
Enter this number
Type in the number above:
Comment (required):