So I worked this out using HTML::Mason Plugins. This is not the solution I was hoping for, as it does not sanitize the arguments before they are parsed, but after. If there is an exploitable piece of code in the argument parsing, it still may cause problems. This is better than nothing, but it does not feel like a true solution.
Adding Plugins to the ApacheHandler:
my $ah = HTML::Mason::ApacheHandler->new (
...
session_use_cookie => 0,
args_method => "mod_perl",
session_args_param => 'session_id',
plugins => [PolMaker::Plugins::SanitizeArgs->new],
);
Plugin code: $context->args
does most of the heavy lifting. Given the input:
?session_id=c45a0309191691cd5b4714c936d0f9a2&foo=bar&baz=pop
We get the following in $context->args
:
['session_id', 'c45a0309191691cd5b4714c936d0f9a2', 'foo', 'bar', 'baz', 'pop']
This also works for POST
requests, and follows the same rules as HTML::Mason's normal parsing. The actual plugin looks like this:
package PolMaker::Plugins::SanitizeArgs;
use base qw(HTML::Mason::Plugin);
my %SANITIZE = (
"session_id" => 1,
## Room for future expansion.
);
sub start_request_hook { ## Executes once per request.
my $self = shift;
my $context = shift;
my @clean_args;
my $next = 0;
foreach my $arg (@{ $context->args } ) {
if (defined($SANITIZE{$arg})) {
$next = 1;
} elsif ($next > 0) {
$arg =~ s/[^\w \d\-\.]//g; # Leave words, digits, dashes and periods.
$next = 0;
}
push @clean_args, $arg;
}
@{$context->args} = @clean_args;
}
1;
Again, this option isn't as optimal as I wanted, but it will work. Additions and enhancements to this "solution" would also be welcomed.