Controller User Input Validation

One of the most important security activity for a web application, according to the OWASP Top Ten security flaws, is to validate all user input. When validating it is important to use a whitelist and not a blacklist approach. That means you should check whether the input has the correct format or includes the allowed values, and reject it if it does not. For example, it could allow plain text and the <b>, <em> and <u> HTML tags to write bold, italic or underlined. Use Rails' whitelist plugin (http://svn.techno-weenie.net/projects/plugins/white_list/) to realize a whitelist HTML check. Ablacklist, in contrast, looks for invalid input or attack signatures, but this can hardly be all-inclusive.
 
 
Rails has its own validation framework. With functions like validates_numericality_of(), which checks whether a value is numerical, you can check the integrity in the model, that means when assigning a value to a property of the model. However, oftentimes integrity has to be checked in the controller, as well, for example when queryingdata or sending back user input. Therefore, the author has created a validation framework which checks the integrity of a value according to what is expected. You can test for a specific type, you can declare a list of allowed values, a minimum and maximum length, or you can make sure that the value has a specific format (with a regular expression). If validation fails, a default value will be returned. The signature of the validation method is the following:
 
parseparam(vpstr, vdefault, vtype, vpositivelist, vmatchregexpr, vmin, vmax)
 
Parameters:
vpstr – the value to be validated
vdefault – will be returned if the validation fails
vtype – the expected type of vpstr. This can be bool (for a Boolean value), int (for an Integer), str (for a string), email (for an email address), htmlescape (to escape HTML characters in vpstr)
vpositivelist – a whitelist with allowed values. This can be an array, as in %w("f","m") for strings, or a range, as in 1..99 for integers, and 'a'..'z' for strings. (optional)
vmatchregexpr – a regular expression to be validated against; only available for thestring type. (optional)
vmin – the minimum length of vpstr. (optional)
vmin – the maximum length of vpstr. (optional)
 
The following shows several examples of how to use the validation method:
 
# A gender can be male or female:
gender = parseparam( params[:gender], "f", "str", %w("m", "f"))
 
# A year can be between 0 and 2007:
year = parseparam( params[:year], 2007, "int", 0..2007)
 
# A first name has to be between 2 and 30 characters in length
# and it has to start with a capital letter, followed by any
# number of characters
fname = parseparam( params[:name], "", "str", nil,
/\A[A-Z]+[A-Za-z.]*\z/, 2, 30)
 
# A file name may be alphanumerical and may contain .-+_
file = parseparam( params[:file], "", "str", nil, /^[\w\.\-\+]+$/)
 
The last example seems to validate for a valid file name, however it is prone to user agent injection, a file name with embedded JavaScript, such as file.txt\%0A<script>alert('hello')</script>, passes the filter. This is due to the widespread belief that ^matches the beginning of a string and $ the end, as in other programming languages. In Ruby, however, these characters match the begining and end of a line, so the above string passes the filter, as it contains a line break (%0A). The correct sequences for Ruby are \A and \z, so the expression from above should read /\A[\w\.\-\+]+\z/.
 
Please download the user input validation framework, you can freely use it and post your comments. Thanks.