This past week, I had the opportunity to attend a couple of user group meetings, both of which featured Jeff Prosise as the speaker. Both meetings were sponsored by INETA. Jeff spoke to the Wednesday Boston .NET User Group meeting on Power ASP.NET 2.0 Programming. Christopher Bowen and Girish Bharadwaj give excellent summaries of this meeting. I enjoyed this meeting as well, but I particularly liked his Thursday New Hampshire .NET User Group meeting topic on Hacked! How Evil People Attack ASP.NET Web Sites.
Jeff is an excellent speaker as he doesn't get bogged down by PowerPoint slides, but instead speaks directly to the developer about the problems and solutions for writing good, secure code. Jeff presented on the topics of hidden field tampering, SQL injection, and cross-site scripting.
Hidden field tampering: I am surprised how many developers haven't heard of this by now, but as Jeff mentioned, he has seen recent cases where this was not guarded against on a site and was exploited. Basically, if you allow sensitive data to be displayed openly in hidden forms, and don't validate or verify the data coming back from the form, you could be affected by a hacker changing the expected value in the hidden field. It's an old trick: change the ticket amount for your flight from $1000.00 to $1.00 and post the form back to the web site, and you have a cheap (illegal, of course!) trip! The key is, as always, never trust input coming from the outside. Remember, trust, but verify. Of course, with ASP.NET, you should use the ViewState to hold
encryptedencoded hidden form values, or better yet, don't pass any sensitive information back to your forms.
Update: As mentioned by Atilla in the comments, ViewState is not encrypted, but Base 64 encoded -- it can be viewed by a hacker. There is a hash value added to the ViewState before being sent back to the client. This is verified back on the server to determine if there was any tampering of data. Once again, though, it is best never to send sensitive information back to the client.
SQL Injection: This is one of those topics that easily prompts someone in the audience to suddenly jump up and run out of the room frantically calling their office to check if they have this problem! If a form field is not checked for input, and you use concatenation of SQL script in any way, you could be open to this exploit. For example, in many samples and other places, you see code similar to this:
sqlQuery = "select count(*) from users where username = '" + username + "' and password = '" + password + "'";
which looks like this when passed in to the database:
select count(*) from users where username = 'George' and password = 'letmein'
This can be exploited by inserting ' or 1=1 --, which changes the meaning:
select count(*) from users where username = '' or 1=1 (remember, -- is a comment, so everything after the 1 is ignored).
This will always evaluate to true. This is worse:
select count(*) from users where username = '' union select name from sysobjects where type = 'u' --
where this will return all table names within your database (SQL Server specific, but similar things can be done with Oracle, etc. as well). This can continue with call xp_cmdshell to delete a file (as Jeff demonstrated) or worse. I have seen it used to upload files, create users, and basically set up shop on your database server! The bottom line is to verify input, use SQLParameter to turn the input into strings rather than active SQL syntax, and run with a least-privileged user (non "SA"!) when calling into the database.
Cross-site scripting: This is one of those exploits that allows a hacker to steal cookies, session information, and other sensitive data. If not checked, a hacker could imbed a <script> tag in your input field or on a query string, and if the input is repeated back on the form after a postback, the hacker will now be able to call this form remotely and obtain sensitive information. A common technique using this exploit is "phishing". A user gets an email from a bank or other trusted entity and is asked to update their account. If a cookie was saved on the user's computer, the link will "appear" to go to the bank site, but instead will take a detour to grab the saved cookie using a <script> tag form post. One variation of phishing is to present a site that looks exactly like the bank site, asking for the user's account information. The solution to this is to, of course, validate user input, but to also use HtmlEncode around anything you retrieve and display on your web site.
Jeff mentioned that Microsoft is now using Validation Layers as one of the layers in an application. This sounds like a great idea! Essentially, all input and sometimes output from the database, should go through this layer for scrubbing and validating before it enters the rest of your business logic and data layers.
At the end of Jeff's presentation, someone asked for more resources on this topic. Here are a few that I know about and have used:
Building Secure Microsoft ASP.NET Applications by Microsoft Patterns and Practices Group
Improving Web Application Security: Threats And Countermeasures by Microsoft Patterns and Practices Group
Writing Secure Code, Second Edition by Michael Howard and David LeBlanc
Recently, I had the pleasure of looking at early beta versions of a new product that helps catch and log these kinds of exploits. Take a look at Peter Blum's Visual Input Security tool for ASP.NET web sites. Some highlights of the tool:
Overall, as Jeff concluded, you have to be prepared, informed, and ready for the security challenges you WILL face in developing ASP.NET web sites. Do all that you can to learn about these issues, and make sure your site is not open to these and many other exploits.