fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2011-05-17 04:01 am

[dw-free] http://bugs.dwscoalition.org/show_bug.cgi?id=2735

[commit: http://hg.dwscoalition.org/dw-free/rev/116559a9f5bb]

http://bugs.dwscoalition.org/show_bug.cgi?id=2735

Stricter handling of suffixes in page referers.

Patch by [personal profile] fu.

Files modified:
  • cgi-bin/weblib.pl
  • htdocs/admin/vgifts/inactive.bml
  • htdocs/admin/vgifts/index.bml
  • htdocs/admin/vgifts/tags.bml
  • t/referer.t
--------------------------------------------------------------------------------
diff -r 2127ee88cfd3 -r 116559a9f5bb cgi-bin/weblib.pl
--- a/cgi-bin/weblib.pl	Tue May 17 10:15:43 2011 +0800
+++ b/cgi-bin/weblib.pl	Tue May 17 10:20:10 2011 +0800
@@ -757,11 +757,19 @@
     # escape any regex characters, like the '.' in '.bml'
     $uri = quotemeta( $uri );
 
+    # check that the end of the uri matches exactly (no extra characters or dir levels)
+    # or else that the uri is followed immediately by additional parameters
+    my $checkend = '(?:$|\\?)';
+
     # allow us to properly check URIs without .bml extensions
     if ( $origuri =~ /\.bml($|\?)/ ) {
-      my $checkend = ( $1 eq '?' ? '' : '(?:$|\\?)' );
-      $uri     =~ s/\\.bml($|\\\?)/$1$checkend/;
-      $referer =~ s/\.bml($|\?)/$1/;
+        $checkend = '' if $1 eq '?';
+        $uri     =~ s/\\.bml($|\\\?)/$1$checkend/;
+        $referer =~ s/\.bml($|\?)/$1/;
+    } elsif ( $uri ) {
+        $uri .= $checkend;
+    } else {
+        $uri = '(/|$)';
     }
 
     return 1 if $LJ::SITEROOT   && $referer =~ m!^\Q$LJ::SITEROOT\E$uri!;
diff -r 2127ee88cfd3 -r 116559a9f5bb htdocs/admin/vgifts/inactive.bml
--- a/htdocs/admin/vgifts/inactive.bml	Tue May 17 10:15:43 2011 +0800
+++ b/htdocs/admin/vgifts/inactive.bml	Tue May 17 10:20:10 2011 +0800
@@ -1,13 +1,14 @@
 <?_code
 {
     use strict;
-    use vars qw($title $body $page $action %GET %POST);
+    use vars qw($title $body $page $baseuri $action %GET %POST);
 
     use DW::VirtualGift;
 
     $title = $ML{'.title'};
     $body = "";
-    $page = "$LJ::SITEROOT/admin/vgifts/inactive";
+    $baseuri = "/admin/vgifts/inactive";
+    $page = "$LJ::SITEROOT$baseuri";
     $action = 'inactive';  # for $postform
 
     # helper routines
@@ -21,9 +22,7 @@
 
     my $loose_refer = sub {
         return 1 unless my $refer = BML::get_client_header('Referer');
-        my ( $getargs ) = ( $refer =~ m/\?(.*)$/ );
-        return LJ::check_referer( $page ) unless $getargs;
-        return LJ::check_referer( "$page?$getargs" );
+        return LJ::check_referer( $baseuri );
     };
 
     my $strict_refer = sub {
diff -r 2127ee88cfd3 -r 116559a9f5bb htdocs/admin/vgifts/index.bml
--- a/htdocs/admin/vgifts/index.bml	Tue May 17 10:15:43 2011 +0800
+++ b/htdocs/admin/vgifts/index.bml	Tue May 17 10:20:10 2011 +0800
@@ -1,13 +1,14 @@
 <?_code
 {
     use strict;
-    use vars qw($title $body $page $action %GET %POST);
+    use vars qw($title $body $page $baseuri $action %GET %POST);
 
     use DW::VirtualGift;
 
     $title = $ML{'.title'};
     $body = "";
-    $page = "$LJ::SITEROOT/admin/vgifts/";
+    $baseuri = "/admin/vgifts/";
+    $page = "$LJ::SITEROOT$baseuri";
     $action = 'index';  # for $postform
 
     # helper routines
@@ -21,18 +22,15 @@
 
     my $loose_refer = sub {
         return 1 unless my $refer = BML::get_client_header('Referer');
-        my ( $getargs ) = ( $refer =~ m/\?(.*)$/ );
         # annoyingly, we get different results for /index vs /
-        return LJ::check_referer( $page ) ||
-            LJ::check_referer( "${page}index" ) unless $getargs;
-
-        return LJ::check_referer( "$page?$getargs" ) ||
-            LJ::check_referer( "${page}index?$getargs" );
+        return LJ::check_referer( $baseuri ) ||
+            LJ::check_referer( "${$baseuri}index" );
     };
 
     my $strict_refer = sub {
         # make sure we have a referer header. check_referer doesn't care.
-        return BML::get_client_header('Referer') && $loose_refer->();
+        my $ret = BML::get_client_header('Referer') && $loose_refer->();
+        return $ret;
     };
 
     my $imgposted = sub {
diff -r 2127ee88cfd3 -r 116559a9f5bb htdocs/admin/vgifts/tags.bml
--- a/htdocs/admin/vgifts/tags.bml	Tue May 17 10:15:43 2011 +0800
+++ b/htdocs/admin/vgifts/tags.bml	Tue May 17 10:20:10 2011 +0800
@@ -1,13 +1,14 @@
 <?_code
 {
     use strict;
-    use vars qw($title $body $page $action %GET %POST);
+    use vars qw($title $body $page $baseuri $action %GET %POST);
 
     use DW::VirtualGift;
 
     $title = $ML{'.title'};
     $body = "";
-    $page = "$LJ::SITEROOT/admin/vgifts/tags";
+    $baseuri = "/admin/vgifts/tags";
+    $page = "$LJ::SITEROOT$baseuri";
     $action = 'tags';  # for $postform
 
     # helper routines
@@ -21,9 +22,7 @@
 
     my $loose_refer = sub {
         return 1 unless my $refer = BML::get_client_header('Referer');
-        my ( $getargs ) = ( $refer =~ m/\?(.*)$/ );
-        return LJ::check_referer( $page ) unless $getargs;
-        return LJ::check_referer( "$page?$getargs" );
+        return LJ::check_referer( $baseuri );
     };
 
     my $strict_refer = sub {
diff -r 2127ee88cfd3 -r 116559a9f5bb t/referer.t
--- a/t/referer.t	Tue May 17 10:15:43 2011 +0800
+++ b/t/referer.t	Tue May 17 10:20:10 2011 +0800
@@ -6,7 +6,7 @@
 require 'ljlib.pl';
 require 'weblib.pl';
 
-plan tests => 18;
+plan tests => 25;
 
 {
     note( '$LJ::SITEROOT not set up. Setting up for the test.' ) unless $LJ::SITEROOT;
@@ -14,39 +14,57 @@
 
     # first argument is the page we want to check against (system-provided)
     # second argument is the page the user said they were coming from
+
+    note( "basic tests" );
     ok( LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page.bml" ), "Visited page with bml extension; uri check has .bml." );
     ok( LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page" ), "Visited page with no bml extension; uri check has .bml" );
-    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page.bml" ), "Visited page with bml extension; uri check has no .bml" );
     ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page" ), "Visited page with no bml extension; uri check has .bml" );
 
 
+    note( "checking ssl" );
     note( '$LJ::SSLROOT not set up. Setting up for the test.' ) unless $LJ::SSLROOT;
     $LJ::SSLROOT ||= "https://$LJ::DOMAIN_WEB";
 
     ok( LJ::check_referer( "/page", "$LJ::SSLROOT/page" ), "Checking the SSLROOT" );
 
 
+    note( "checking domain / siteroot " );
     my $somerandomsiteroot = "http://www.somerandomsite.org";
     ok( LJ::check_referer( "", $LJ::SITEROOT ), "Check if SITEROOT is on our site" );
     ok( LJ::check_referer( "", "$LJ::SITEROOT/page" ), "Check if any page on our site is on our site" );
     ok( LJ::check_referer( "", $LJ::SSLROOT ), "Check if SSLROOT is on our site" );
     ok( ! LJ::check_referer( "", $somerandomsiteroot ), "Check if somerandomsite is on our site" );
+    ok( ! LJ::check_referer( "", "${LJ::SITEROOT}.other.tld" ), "Check if another site which begins with our SITEROOT is on our site" );
+    ok( ! LJ::check_referer( "/page", "/page" ), "Passed in a bare URI as a referer" );
 
+
+    note( "checking extensions" );
     ok( ! LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page.bmls" ), "Visited page with invalid extension .bmls; uri should be page.bml." );
     ok( ! LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page.html" ), "Visited page with invalid extension .html; uri should be page.bml." );
 
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page.bml" ), "Visited page with bml extension; uri check has no .bml" );
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page.bmls" ), "Visited page with invalid extension .bmls (bml+suffix)" );
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page.html" ), "Visited page with invalid extension .html (nothing that looks like bml)" );
 
-    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page.bmls" ), "Visited page with invalid extension .bmls; uri can be page.*" );
-    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page.html" ), "Visited page with invalid extension .html; uri can be page.*" );
 
-
-    ok( ! LJ::check_referer( "/page", "/page" ), "Passed in a bare URI as a referer" );
+    note( "checking for partial matches (should not match)" );
     ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/prefix-page" ), "Visited URL does not match referer URL. (Added prefix)" );
-    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page?argument" ), "Visited URL matches referer URL (with arguments)" );
-
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page-suffix" ), "Visited URL does not match referer URL. (Added suffix)" );
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page/other" ), "Visited URL does not match referer URL. (Added directory level)" );
 
     ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/" ), "Visited bare SITEROOT" );
     ok( ! LJ::check_referer( "/page", "$somerandomsiteroot/page" ), "Visited SITEROOT is not from our domain" );
+
+
+    note( "checking for URL arguments" );
+    # Argument tests where uri does not have an argument
+    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page?argument" ), "Visited URL matches referer URL (with arguments)" );
+    ok( ! LJ::check_referer( "/page", "$LJ::SITEROOT/page.bml?argument" ), "Visited .bml URL with arguments matches allowed URL" );
+    ok( LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page?argument" ), "Visited non-bml URL with arguments matches allowed .bml URL" );
+    ok( LJ::check_referer( "/page.bml", "$LJ::SITEROOT/page.bml?argument" ), "Visited .bml URL with arguments matches allowed .bml URL" );
+
+    # Tricks with two question marks in referer
+    ok( LJ::check_referer( "/page", "$LJ::SITEROOT/page?argument?suffix" ), "Visited page has second question mark followed by suffix; uri check has no arguments" );
 }
 
 1;
--------------------------------------------------------------------------------

Post a comment in response:

This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

If you are unable to use this captcha for any reason, please contact us by email at support@dreamwidth.org