Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Plack::App::File: Fix a security issue by not pruning trailing slashes #446

Merged
merged 1 commit into from Feb 7, 2014

Conversation

Projects
None yet
3 participants
Contributor

avar commented Feb 7, 2014

Before this Plack::App::File would prune trailing slashes via its split
invocation. I.e. it would think this:

$ perl -MData::Dumper -wle 'print Dumper [split /[\\\/]/, shift]' a/file.txt
$VAR1 = [
          'a',
          'file.txt'
        ];

Was the same as:

$ perl -MData::Dumper -wle 'print Dumper [split /[\\\/]/, shift]' a/file.txt///
$VAR1 = [
          'a',
          'file.txt'
        ];

This can. turn into a nasty code exposure issue if you e.g. have an app
that basically does this:

1. I'd do a regex /.txt.pl\z/ on a file to see if it was a text file
2. If so, do magic to generate text file via perl
3. Else it's not a /.txt.pl\z/ file, so it must be some other static
   file with a different extension
4. Serve it up with Plack::Middleware::Static

This is also not how other webservers or Unix utilities work:

$ touch /tmp/foo.txt
$ file /tmp/foo.txt
/tmp/foo.txt: empty
$ file /tmp/foo.txt/
/tmp/foo.txt/: ERROR: cannot open `/tmp/foo.txt/' (Not a directory)

This resolves issue #405 that I filed around 9 months ago. I was
previously working around it in my own code by doing:

{
    # Let's see if someone's trying to be evil by
    # requesting e.g. /index.html/ instead of
    # /index.html. We don't want to fall through
    # and just serve up the raw content.
    my $plack_app_file = Plack::App::File->new({ root => PLACK_WEBSERVER_DOCUMENT_ROOT() });
    my ($file) = $plack_app_file->locate_file($env);
    if (
        # We'll get a reference if it's a full
        # Plack response. I.e. a 404 or whatever.
        ref $file ne 'ARRAY'
        and
        # WTF once we canonicalize the file and it
        # looks like a Mason handled path let's
        # not accept it, because we don't want to
        # serve up the raw unprocessed Mason page
        # via this hack.
        $file =~ $mason_handles_this_path_rx
    ) {
        TELL "Middleware::Static: Path <$path> request, doesn't match <$mason_handles_this_path_rx>, but actually resolves to it via resolved file <$file>" if DEBUG;
        # Tells our app to just serve up a
        #400. Apache would do a 404 but I think
        # these requests are bad, so say so.
        $env->{$magic_marker_to_return_400} = 1;
        return;
    }
}
@avar avar Plack::App::File: Fix a security issue by not pruning trailing slashes
Before this Plack::App::File would prune trailing slashes via its split
invocation. I.e. it would think this:

    $ perl -MData::Dumper -wle 'print Dumper [split /[\\\/]/, shift]' a/file.txt
    $VAR1 = [
              'a',
              'file.txt'
            ];

Was the same as:

    $ perl -MData::Dumper -wle 'print Dumper [split /[\\\/]/, shift]' a/file.txt///
    $VAR1 = [
              'a',
              'file.txt'
            ];

This can. turn into a nasty code exposure issue if you e.g. have an app
that basically does this:

    1. I'd do a regex /.txt.pl\z/ on a file to see if it was a text file
    2. If so, do magic to generate text file via perl
    3. Else it's not a /.txt.pl\z/ file, so it must be some other static
       file with a different extension
    4. Serve it up with Plack::Middleware::Static

This is also not how other webservers or Unix utilities work:

    $ touch /tmp/foo.txt
    $ file /tmp/foo.txt
    /tmp/foo.txt: empty
    $ file /tmp/foo.txt/
    /tmp/foo.txt/: ERROR: cannot open `/tmp/foo.txt/' (Not a directory)

This resolves issue #405 that I filed around 9 months ago. I was
previously working around it in my own code by doing:

    {
        # Let's see if someone's trying to be evil by
        # requesting e.g. /index.html/ instead of
        # /index.html. We don't want to fall through
        # and just serve up the raw content.
        my $plack_app_file = Plack::App::File->new({ root => PLACK_WEBSERVER_DOCUMENT_ROOT() });
        my ($file) = $plack_app_file->locate_file($env);
        if (
            # We'll get a reference if it's a full
            # Plack response. I.e. a 404 or whatever.
            ref $file ne 'ARRAY'
            and
            # WTF once we canonicalize the file and it
            # looks like a Mason handled path let's
            # not accept it, because we don't want to
            # serve up the raw unprocessed Mason page
            # via this hack.
            $file =~ $mason_handles_this_path_rx
        ) {
            TELL "Middleware::Static: Path <$path> request, doesn't match <$mason_handles_this_path_rx>, but actually resolves to it via resolved file <$file>" if DEBUG;
            # Tells our app to just serve up a
            # 400. Apache would do a 404 but I think
            # these requests are bad, so say so.
            $env->{$magic_marker_to_return_400} = 1;
            return;
        }
    }
bc1731d

Coverage Status

Coverage decreased (-0.09%) when pulling bc1731d on avar:avar/fix-issue-405 into 9c8a5bc on plack:master.

@miyagawa miyagawa added a commit that referenced this pull request Feb 7, 2014

@miyagawa miyagawa Merge pull request #446 from avar/avar/fix-issue-405
Plack::App::File: Fix a security issue by not pruning trailing slashes
458eb93

@miyagawa miyagawa merged commit 458eb93 into plack:master Feb 7, 2014

1 check passed

default The Travis CI build passed
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment