I'm using HTML::Mason
, and after a recent security audit, it was discovered that some of our software is vulnerable to a header injection. Specifically this is related to the session_id
argument, which is passed around through GET
and POST
requests.
I've tried to modify the environment in my handler()
method from a custom handler, but the Apache2::RequestRec
is already created, so it doesn't pick up the changes.
Is there a good way to sanitize all of the input into HTML::Mason at the handler level?
HTML::Mason::DGIHandler
and it caused issues when used with both POST
and GET
data. I was able to find a working patch, but I don't find it optimal. I'll post the response shortly - Jack M. 2012-04-11 19:01
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.