MediaWiki  REL1_20
IEUrlExtension.php
Go to the documentation of this file.
00001 <?php
00044 class IEUrlExtension {
00062         public static function areServerVarsBad( $vars, $extWhitelist = array() ) {
00063                 // Check QUERY_STRING or REQUEST_URI
00064                 if ( isset( $vars['SERVER_SOFTWARE'] )
00065                         && isset( $vars['REQUEST_URI'] )
00066                         && self::haveUndecodedRequestUri( $vars['SERVER_SOFTWARE'] ) )
00067                 {
00068                         $urlPart = $vars['REQUEST_URI'];
00069                 } elseif ( isset( $vars['QUERY_STRING'] ) ) {
00070                         $urlPart = $vars['QUERY_STRING'];
00071                 } else {
00072                         $urlPart = '';
00073                 }
00074 
00075                 if ( self::isUrlExtensionBad( $urlPart, $extWhitelist ) ) {
00076                         return true;
00077                 }
00078 
00079                 // Some servers have PATH_INFO but not REQUEST_URI, so we check both
00080                 // to be on the safe side.
00081                 if ( isset( $vars['PATH_INFO'] )
00082                         && self::isUrlExtensionBad( $vars['PATH_INFO'], $extWhitelist ) )
00083                 {
00084                         return true;
00085                 }
00086 
00087                 // All checks passed
00088                 return false;
00089         }
00090 
00100         public static function isUrlExtensionBad( $urlPart, $extWhitelist = array() ) {
00101                 if ( strval( $urlPart ) === '' ) {
00102                         return false;
00103                 }
00104 
00105                 $extension = self::findIE6Extension( $urlPart );
00106                 if ( strval( $extension ) === '' ) {
00107                         // No extension or empty extension
00108                         return false;
00109                 }
00110 
00111                 if ( in_array( $extension, array( 'php', 'php5' ) ) ) {
00112                         // Script extension, OK
00113                         return false;
00114                 }
00115                 if ( in_array( $extension, $extWhitelist ) ) {
00116                         // Whitelisted extension
00117                         return false;
00118                 }
00119 
00120                 if ( !preg_match( '/^[a-zA-Z0-9_-]+$/', $extension ) ) {
00121                         // Non-alphanumeric extension, unlikely to be registered.
00122                         //
00123                         // The regex above is known to match all registered file extensions
00124                         // in a default Windows XP installation. It's important to allow
00125                         // extensions with ampersands and percent signs, since that reduces
00126                         // the number of false positives substantially.
00127                         return false;
00128                 }
00129 
00130                 // Possibly bad extension
00131                 return true;
00132         }
00133 
00141         public static function fixUrlForIE6( $url, $extWhitelist = array() ) {
00142                 $questionPos = strpos( $url, '?' );
00143                 if ( $questionPos === false ) {
00144                         $beforeQuery = $url . '?';
00145                         $query = '';
00146                 } elseif ( $questionPos === strlen( $url ) - 1 ) {
00147                         $beforeQuery = $url;
00148                         $query = '';
00149                 } else {
00150                         $beforeQuery = substr( $url, 0, $questionPos + 1 );
00151                         $query = substr( $url, $questionPos + 1 );
00152                 }
00153 
00154                 // Multiple question marks cause problems. Encode the second and
00155                 // subsequent question mark.
00156                 $query = str_replace( '?', '%3E', $query );
00157                 // Append an invalid path character so that IE6 won't see the end of the
00158                 // query string as an extension
00159                 $query .= '&*';
00160                 // Put the URL back together
00161                 $url = $beforeQuery . $query;
00162                 if ( self::isUrlExtensionBad( $url, $extWhitelist ) ) {
00163                         // Avoid a redirect loop
00164                         return false;
00165                 }
00166                 return $url;
00167         }
00168 
00193         public static function findIE6Extension( $url ) {
00194                 $pos = 0;
00195                 $hashPos = strpos( $url, '#' );
00196                 if ( $hashPos !== false ) {
00197                         $urlLength = $hashPos;
00198                 } else {
00199                         $urlLength = strlen( $url );
00200                 }
00201                 $remainingLength = $urlLength;
00202                 while ( $remainingLength > 0 ) {
00203                         // Skip ahead to the next dot
00204                         $pos += strcspn( $url, '.', $pos, $remainingLength );
00205                         if ( $pos >= $urlLength ) {
00206                                 // End of string, we're done
00207                                 return false;
00208                         }
00209 
00210                         // We found a dot. Skip past it
00211                         $pos++;
00212                         $remainingLength = $urlLength - $pos;
00213 
00214                         // Check for illegal characters in our prospective extension,
00215                         // or for another dot
00216                         $nextPos = $pos + strcspn( $url, "<>\\\"/:|?*.", $pos, $remainingLength );
00217                         if ( $nextPos >= $urlLength ) {
00218                                 // No illegal character or next dot
00219                                 // We have our extension
00220                                 return substr( $url, $pos, $urlLength - $pos );
00221                         }
00222                         if ( $url[$nextPos] === '?' ) {
00223                                 // We've found a legal extension followed by a question mark
00224                                 // If the extension is NOT exe, dll or cgi, return it
00225                                 $extension = substr( $url, $pos, $nextPos - $pos );
00226                                 if ( strcasecmp( $extension, 'exe' ) && strcasecmp( $extension, 'dll' ) &&
00227                                         strcasecmp( $extension, 'cgi' ) )
00228                                 {
00229                                         return $extension;
00230                                 }
00231                                 // Else continue looking
00232                         }
00233                         // We found an illegal character or another dot
00234                         // Skip to that character and continue the loop
00235                         $pos = $nextPos;
00236                         $remainingLength = $urlLength - $pos;
00237                 }
00238                 return false;
00239         }
00240 
00259         public static function haveUndecodedRequestUri( $serverSoftware ) {
00260                 static $whitelist = array(
00261                         'Apache',
00262                         'Zeus',
00263                         'LiteSpeed' );
00264                 if ( preg_match( '/^(.*?)($|\/| )/', $serverSoftware, $m ) ) {
00265                         return in_array( $m[1], $whitelist );
00266                 } else {
00267                         return false;
00268                 }
00269         }
00270 
00271 }