[cgiapp] LinkIntegrity vs ValidateQuery plugin?

Mark Stosberg mark at summersault.com
Tue Apr 14 11:16:17 EDT 2009


As I considered this problem space further, I'm wondering if I should be
following the approach of the LinkIntegrity plugin instead. It adds a
checksum to internal application links, which allows tampering to be
detected:

http://search.cpan.org/dist/CGI-Application-Plugin-LinkIntegrity/lib/CGI/Application/Plugin/LinkIntegrity.pm

Pros for LinkIntegrity:
 - If an query param is missing, you can tell whether it's because the
   application failed to send it, or the user tampered with it.
 - It's consistent and to use...the syntax is the same for all links.

Cons for LinkIntegrity:
 - Adding a required checksum to existing link means to old link quits working,
   and backward compatibility may be lost.
 - It currently seems to be implemented to require the integrity checks
   to be turned on at the module level. I'd like control at the
   run-mode level. (I'm sure I could patch or fork to fix this). 

I think the conclusion I'm coming to is that the approaches don't need
to be either/or, but rather they complement each other. Only
LinkIntegrity can tell me if a query has been tampered with or not.

However, only validation can check if in fact I have all parameters I
need in the right format. That protects against the case where my
application generates a link with a valid checksum, but somehow has the
wrong data in it. If I skipped validation in the receiving run mode,  I
open myself up for a garbage-in/garbage-out problem, or perhaps worse.

Anyone here using LinkIntegrity? How are you doing lightweight query
validation?

    Mark

On Fri, 10 Apr 2009 18:13:59 -0400
Mark Stosberg <mark at summersault.com> wrote:

> 
> I'm considering producing a CGI::Application plugin for light weight query
> validation using Params::Validate. I've drafted the POD for it, and
> that's below.  
> 
> The implementation would include one novel technical concept that I
> haven't notice in use before in a CGI::Application project.
> 
> We wanted to clean up the API, so that instead of this:
> 
>  my $err_page = $self->validate_query;
>  return $err_page if $err_page
> 
> We could just do this:
> 
>  $self->validate_query;
> 
> This means we had to find some other way to interrupt the flow and
> return our error page. The solution is to write a suicide note and then
> pull the trigger. Or rather, in validate_query(), if validation fails,
> we do a just-in-time setting of error_mode(), and then die, which
> interrupts the flow and triggers the error_mode to be called.
> 
> The solution seems reasonable, as a general error_mode() would still
> remain in effect, and if some reason you don't want interrupt the flow,
> just trap the exception the usual way:
> 
>  eval { $self->validate_query; }
> 
> I hadn't considered it until now, but perhaps we could also use
> Exception::Class so users could easily distinquish between
> death-by-validation failure and unexpected-death.
> 
> Now that I've thought of this approach, it makes me want to apply to to
> the ::ValidateRM interface.  Anyone see a reason not to take this
> approach for this plugin, or ValidateRM?
> 
> 
> ####
> 
> =head1 NAME
> 
> CGI::Application::Plugin::ValidateQuery
> 
> =head1 SYNOPSIS
> 
>  sub setup {
>      my $self = shift;
>  
>      $self->validate_query_config(
>             # define a page to show for invalid queries, or default to
>             # serving a plain, internal page
>             error_mode =>  'my_invalid_query_run_mode',
>             log_level  => 'notice',
>      );
> 
>  }
> 
>  sub my_run_mode {
>     my $self = shift;
> 
>     # validate the query and return a standard error page on failure.
>     $self->validate_query(
>             pet_id    => SCALAR,
>             direction => { type => SCALAR, default => 'up' },
>     );
> 
>     # go on with life...
> 
>  }
> 
> =head1 DESCRIPTION
> 
> This plugin is for small query validation tasks. For example, perhaps
> you link to a page where a "pet_id" is required, and you need to reality
> check that this exists or return essentially a generic error message to
> the user.
> 
> Even if your application generates the link, it may become altered
> through tampering, malware, or other unanticipated events. 
> 
> This plugin uses <Params::Validate> to validate the query string.  You
> can define your own error page to return on failure, or we'll supply a
> plain default one internally. 
> 
> You may also define a C<log_level>, if you do, we will also log each
> validation failure at the chosen level like this:
> 
>  $self->log->$loglevel("Query validation failed: $@");
> 
> L<CGI::Application::Plugin::LogDispatch> is one plugin which implements
> this logging API.
> 
> =head2 validate_query 
> 
>     $self->validate_query(
>                             pet_id => SCALAR,
>                             type   => { type => SCALAR, default => 'food' },
>                             log_level => 'critical', # optional
>      );
> 
> Validates C<< $self->query >> using L<Params::Validate>. If any required
> query param is missing or invalid, the  run mode defined with C<<
> validate_query_config >> will be used, or a plain internal page will be
> returned by default. C<< validate_query_config >> is usually called in
> C<< setup() >>, or a in a project super-class.
> 
> If <log_level> is defined, it will override the the log file provided in
> C<< validate_query_config >> and log a validation failure at that log
> evel 
> 
> If you set a default, the query will be modified with the new value.
> 
> =cut
> 
> sub validate_query {
> 
> }
> 
> =head2 IMPLENTATION NOTES
> 
> We set "local $Params::Validate::NO_VALIDATION = 0;" to be sure that
> Params::Validate works for us, even if is globally disabled.
> 
> To alter the application flow when validation fails, we set
> 'error_mode()' at the last minute, and then die, so the error mode is
> triggered. Other uses of error_mode() should continue to work as normal.
> 
> This module is intended to be use for simple query validation tasks,
> such as a link with  query string with a small number of arguments. For
> larger validation tasks, especially for processing for submissions using
> L< Data::FormValidator > is recommended, along with L<
> CGI::Application::ValidateRM > if you using CGI::Application. 
> 
> =head2 FUTURE
> 
> This concept could be extended to all check values set through
> $self->param(), or through $ENV{PATH_INFO} .
> 
> This plugin does handle file upload validations, and won't in the
> future.
> 
> Providing untainting is not a goal of this module, but if it's easy and
> someone else provides a patch, perhaps support will be added. 
> 
> =head1 AUTHOR
> 
> Mark Stosberg C<< mark at summersault.com >>
> 
> 
> 
> #####  CGI::Application community mailing list  ################
> ##                                                            ##
> ##  To unsubscribe, or change your message delivery options,  ##
> ##  visit:  http://lists.openlib.org/mailman/listinfo/cgiapp    ##
> ##                                                            ##
> ##  Web archive:   http://lists.openlib.org/pipermail/cgiapp/   ##
> ##  Wiki:          http://cgiapp.erlbaum.net/                 ##
> ##                                                            ##
> ################################################################
> 
> 


-- 
 . . . . . . . . . . . . . . . . . . . . . . . . . . . 
   Mark Stosberg            Principal Developer  
   mark at summersault.com     Summersault, LLC     
   765-939-9301 ext 202     database driven websites
 . . . . . http://www.summersault.com/ . . . . . . . .




More information about the cgiapp mailing list