The Center for Education and Research in Information Assurance and Security (CERIAS)

The Center for Education and Research in
Information Assurance and Security (CERIAS)

Optional Client-Side Input Validation That Matches Server-side Validation

Share:

It is common practice to make forms more user-friendly by giving immediate feedback on the inputs with client-side scripting.  Everyone with a bit of secure programming knowledge knows, however, that the server side needs to do the final input validation.  If the two validations are not equivalent, then an input that passes client-side validation may be rejected later, confusing and annoying the customer, or the client-side validation may be needlessly restrictive.  Another problem is when the form stops working if JavaScript is disabled, due to the way input validation was attempted.

I was delighted to discover that the regular expression syntax in JavaScript and Ruby match, and the matching differs only in greedy vs non-greedy behavior, and not whether a match is possible or not.  This means that regular expressions describing a white list of correct inputs can be used for both (this probably works for Perl, Python and PHP as well but I haven’t checked).

In the code for ReAssure, all inputs are defined by classes that create the html for forms, as well as perform input validation.  This means that the regular expression can be defined in a single place, when the class is instantiated:

   def initialize(...)
      (...)
      @regexp = Regexp.new(/^\d+$/) # positive integer
   end

This regular expression can be used to perform the initial server-side input validation:

   def validate(input) 
      if input == nil
         unescaped = default()
      else 
         unescaped = CGI.unescapeHTML(input.to_s.strip)
      end
      unescaped.scan(@regexp) { |match|
         return @value = match.untaint
      }
      if input != ''
         raise 'Input "' + @ui_name + '" is not valid'
      end
   end

To perform client-side input validation, the onblur event is used to trigger validation when focus is lost.  The idea is to make the input red and bold (for color-blind people) when validation fails, and green when it passes.  The onfocus event is used to restore the input to a neutral state while editing (this is the Ruby code that generates the form html):

   def form
      $cgi.input('NAME'=>@name, 'VALUE'=>to_html(), 'onblur' => onblur(),
          'onfocus' => onfocus())
   end

   def onblur()
      return "if (this.value.search(/" + @regexp.source + "/) < 0) 
          {this.className = 'bad'} else {this.className = 'good'};"
   end

   def onfocus()
      return "this.className = 'normal';"
   end

where the classes “bad”, “good” and “normal” are specified in a style sheet (CSS). 
There are cases when more validation may happen later on the server side, e.g., if an integer must match an existing key in a database that the user may be allowed to reference.  Could the extra validation create a mismatch?  Perhaps.  However, in these cases the client-side interface should probably be a pre-screened list and not a free-form input, so the client would have to be malicious to fail server-side validation.  It is also possible to add range (for numbers) and size (for strings) constraints in the “onblur” JavaScript.  In the case of a password field, the JavaScript contains several checks matching the rules on the server side.  So, a lone regular expression may not be sufficient for complete input validation, but it is a good starting point.

Note that the form still works even if JavaScript is disabled!  As you can see, it is easy to perform client-side validation without forcing everyone to turn on JavaScript wink

Comments

Posted by Michael Schuerig
on Saturday, June 9, 2007 at 06:47 AM

I’ve published a Rails plugin “ages” ago that uses reflection to mirror model-level validation in the browser. For an introduction, see

http://schuerig.de/michael/blog/index.php/2006/12/15/rails-almost-automatic-client-side-validation/

Posted by Pascal Meunier
on Wednesday, June 13, 2007 at 06:51 AM

Michael,
I wasn’t aware of your work.  I’m glad that’s available for Rails.  Your plugin sounds easy to use and less work in some cases than what I described, if a little more opaque.  I hope it will be popular.  I think that the central idea of both our designs, changing only the class of the elements, has been validated :;

Leave a comment

Commenting is not available in this section entry.