Moody: inconsistent URL coding of tokens

I want to access a resource in the Restful API, where the resource identifier contains special characters. Therefore, I have url_encoding identifier, but I get inconsistent Mojolicious auto-decoding behavior for placeholders.

Below is a test script that checks for a simple resource identifier that contains a space, one with a plus and one with a slash. I send url_encoding each of them before sending my request, but the 2nd number does not work for various reasons.

#!/usr/bin/env perl

use strict;
use warnings;
use v5.10;

use Data::Dump qw(pp);
use Mojolicious::Lite;
use Mojo::UserAgent;
use Test::Exception;
use Test::More;
use URL::Encode qw(url_encode url_decode);
use WWW::Mechanize;

# Case 1: Access a resource using Standard Placeholders
get '/my/app/standard_placeholder/:id' => sub {
    my $c = shift;

    my $id_raw     = $c->stash('id');
    my $id_decoded = url_decode($id_raw);

    $c->render( json => { raw => $id_raw, decoded => $id_decoded } );
};

# Shut the server down.
get '/my/api/shutdown' => sub {
    exit 0;
};

# Fork for Client and Server
if ( my $pid = fork ) {
    note "Waiting for the server to start";
    sleep 2;

    run_test();

    # Clean up server process and we’re done
    waitpid( $pid, 0 );

} else {
    local @ARGV = qw(daemon);

    app->log( Mojo::Log->new( path => "$0.log", level => 'debug' ) );
    app->start;
}

exit 0;

### Client

sub run_test {
    plan tests => 2;

    my $ua         = Mojo::UserAgent->new();
    my $server_url = 'http://127.0.0.1:3000';

    # Standard Placeholders:  ([^/.]+)
    # Relaxed Placeholders:   ([^/]+)
    # Wildcard Placeholders:  (.+)

    subtest 'Standard Placeholders testing url_encoding of route identifiers' => sub {
        my @ids = (
            "foobar",    #
            "a space",
            "a+plus",
            "a/slash",
        );

        plan tests => 3 * @ids;

        for my $id (@ids) {
            my $id_encoded = url_encode($id);
            my $tx         = $ua->get("$server_url/my/app/standard_placeholder/$id_encoded");

        SKIP: {
                is( $tx->res->code, 200, "Fetch Resource at " . pp($id) )
                    or skip "Error in response", 2;

                is( $tx->res->json->{raw},     $id_encoded, "json->{raw} eq " . pp($id_encoded) );
                is( $tx->res->json->{decoded}, $id,         "json->{decoded} eq " . pp($id) );
            }
        }
    };

    subtest 'Shutdown the server' => sub {
        plan tests => 2;

        dies_ok {
            my $mech = WWW::Mechanize->new( timeout => 3 );
            $mech->get("$server_url/my/api/shutdown");
        }
        'shutdown occurred';

        like $@, qr{Error GETing .*?shutdown: Server closed connection without sending any data back},
            'detected closed connection';
    };
}

1;

And the conclusion:

mhall@dev19:~$ ./mojo_placeholders.pl
# Waiting for the server to start
Server available at http://127.0.0.1:3000
1..2
# Subtest: Standard Placeholders testing url_encoding of route identifiers
    1..12
    ok 1 - Fetch Resource at "foobar"
    ok 2 - json->{raw} eq "foobar"
    ok 3 - json->{decoded} eq "foobar"
    ok 4 - Fetch Resource at "a space"
    ok 5 - json->{raw} eq "a+space"
    ok 6 - json->{decoded} eq "a space"
    ok 7 - Fetch Resource at "a+plus"
    not ok 8 - json->{raw} eq "a%2Bplus"
    #   Failed test 'json->{raw} eq "a%2Bplus"'
    #   at ./mojo_placeholders.pl line 89.
    #          got: 'a+plus'
    #     expected: 'a%2Bplus'
    not ok 9 - json->{decoded} eq "a+plus"
    #   Failed test 'json->{decoded} eq "a+plus"'
    #   at ./mojo_placeholders.pl line 90.
    #          got: 'a plus'
    #     expected: 'a+plus'
    not ok 10 - Fetch Resource at "a/slash"
    #   Failed test 'Fetch Resource at "a/slash"'
    #   at ./mojo_placeholders.pl line 85.
    #          got: '404'
    #     expected: '200'
    ok 11 # skip Error in response
    ok 12 # skip Error in response
    # Looks like you failed 3 tests of 12.
not ok 1 - Standard Placeholders testing url_encoding of route identifiers
#   Failed test 'Standard Placeholders testing url_encoding of route identifiers'
#   at ./mojo_placeholders.pl line 93.
# Subtest: Shutdown the server
    1..2
    ok 1 - shutdown occurred
    ok 2 - detected closed connection
ok 2 - Shutdown the server
# Looks like you failed 1 test of 2.

Any suggestions on how to approach this?

+4
source share
1 answer

, . / vs %2F - . https://groups.google.com/forum/#!topic/python-web-sig/IAPhwezOJ7I , Mojolicious CVE https://www.cvedetails.com/cve/CVE-2011-1589/. , , / . , ( , ) Mojolicious , , . .

#!/usr/bin/env perl
use Mojo::Base -strict;

use Mojolicious::Lite;
use Mojo::Util qw(url_escape url_unescape);

use Test::More;
use Test::Mojo;

my $cb = sub {
    my $c = shift;

    my $id_raw     = $c->stash('id');
    my $id_decoded = url_unescape $id_raw;

    $c->render( json => { raw => $id_raw, decoded => $id_decoded } );
};
get '/standard/:id' => $cb;
get '/relaxed/#id'  => $cb;
get '/wildcard/*id' => $cb;


# Standard Placeholders:  ([^/.]+)
# Relaxed Placeholders:   ([^/]+)
# Wildcard Placeholders:  (.+)

my $t = Test::Mojo->new;

my @ids = (
    "foobar",
    "a space",
    "a+plus",
    "a/slash",
);

plan tests => 3;

for my $type (qw/standard relaxed wildcard/) {
  subtest "Type $type" => sub {
    plan tests => 4 * @ids;

    for my $id (@ids) {
      my $id_encoded = url_escape $id;
      $t->get_ok("/$type/$id_encoded")
        ->status_is(200)
        ->json_is('/raw',     $id_encoded, "$type raw test for $id_encoded")
        ->json_is('/decoded', $id,         "$type decoded test for $id");
    }
  };
}

I did not fix your tests, I just ported them as written (and expanded for all three types of placeholders).

+2
source

Source: https://habr.com/ru/post/1693751/


All Articles