In part 1, I gave an overview of the similarities in securing a good night club and a website and in part 2 I gave an overview of what we, as developers, can do to secure our websites. In this final part, I give details on how we should be doing the most important (and mundane) part of securing our websites:
1. Input Validation (Continued)
One important fact that many web developers fail to take on board, is that everything you receive from the client is a string; Query strings, post back values and cookies. It may look like something else, but it’s actually a little crack in the armour of your website.For example, a query string of “?id=56” doesn’t mean that id is equal to the integer 56, only it’s string form. It can just as easily be manipulated to read “?id=Bob+The+Builder” or the more vicious “id=’);drop table Users;”. If you’ve ever used string concatenation in a SQL statement, your blood should have just run cold!
An excellent habit to get into is to convert every parameter you need as early as possible in the request and use that value from that point on, if the value can’t be converted then throw an exception to stop processing the request. This is one of your websites bouncers, it’ll let through good values but prevent the troublemakers from ruining it for everyone.
This type of conversion is simple, but can be a little long winded to do in a best practice way. The two most common ways I see of doing this in .Net is by using the Convert class or the target types Parse method. These are nice quick one line commands to parse a string into an integer, such as:
1: int id = Convert.ToInt32(Request.QueryString["id"]);
1: int id=0;
2: try
3: {
4: id = Convert.ToInt32(Request.QueryString["id"]);
5: }
6: catch(FormatException fex)
7: {
8: throw new NotSupportedException("The querystring parameter 'id' must be an integer value");
9: }
So to avoid the exception there’s now (in .Net 2.0) TryParse:
1: int id = 0;
2: if (!Int32.TryParse(value, out id)) id = 0;
Of course, this is exactly why the programming gods gave us the concept of Refactoring and Separation of Concerns, you can easily write a reusable wrapper method around the TryParse functionality to make it easier to code with. Thanks to the good people of Microsoft it’s trivial to create an Extension method to provide the functionality to all strings:
1: /// <summary>
2: /// Gets the Int32 value stored in the string
3: /// </summary>
4: /// <param name="value">The string to parse</param>
5: /// <param name="defaultValue">The default value if the the given value cannot be parsed</param>
6: /// <returns>
7: /// The integer represented by the string, otherwise the default value
8: /// </returns>
9: public static Int32 ToInt32(this string value, Int32 defaultValue)
10: {
11: if (string.IsNullOrEmpty(value)) return defaultValue;
12: Int32? result = null;
13: Int32 temp;
14: if (Int32.TryParse(value, out temp)) result = temp;
15: return result ?? defaultValue;
16: }
1: int id = Request.QueryString["id"].ToInt32(0);
To save everyone and their dog from creating versions of these wrappers, I’ve created a small class that provides localization aware type conversion methods.
Attachment: Type Converter Helper
Conversion Performance
I know that some developers feel particularly attached to their ‘Convert’ and ‘Parse’ methods so I’ve created a little performance comparison app and gathered some performance statistics:Method | 5000 Successful Parses (“12345”) | 5000 Failed Conversions (“Not An Integer”) |
Convert | 6ms | 52s |
Parse | 7ms | 54s |
TryParse | 6ms | 6ms |
TryParse (Extension) | 6ms | 6ms |
The application I used to create these numbers is included in the helper library project.
No comments:
Post a Comment
Got something to say? Let it out then!
Comments are moderated, so it may take a while to for them to be displayed here!