MediaWiki  REL1_19
IEUrlExtension.php
Go to the documentation of this file.
00001 <?php
00002 
00024 class IEUrlExtension {
00042         public static function areServerVarsBad( $vars, $extWhitelist = array() ) {
00043                 // Check QUERY_STRING or REQUEST_URI
00044                 if ( isset( $vars['SERVER_SOFTWARE'] )
00045                         && isset( $vars['REQUEST_URI'] )
00046                         && self::haveUndecodedRequestUri( $vars['SERVER_SOFTWARE'] ) )
00047                 {
00048                         $urlPart = $vars['REQUEST_URI'];
00049                 } elseif ( isset( $vars['QUERY_STRING'] ) ) {
00050                         $urlPart = $vars['QUERY_STRING'];
00051                 } else {
00052                         $urlPart = '';
00053                 }
00054 
00055                 if ( self::isUrlExtensionBad( $urlPart, $extWhitelist ) ) {
00056                         return true;
00057                 }
00058 
00059                 // Some servers have PATH_INFO but not REQUEST_URI, so we check both
00060                 // to be on the safe side.
00061                 if ( isset( $vars['PATH_INFO'] )
00062                         && self::isUrlExtensionBad( $vars['PATH_INFO'], $extWhitelist ) )
00063                 {
00064                         return true;
00065                 }
00066 
00067                 // All checks passed
00068                 return false;
00069         }
00070 
00080         public static function isUrlExtensionBad( $urlPart, $extWhitelist = array() ) {
00081                 if ( strval( $urlPart ) === '' ) {
00082                         return false;
00083                 }
00084 
00085                 $extension = self::findIE6Extension( $urlPart );
00086                 if ( strval( $extension ) === '' ) {
00087                         // No extension or empty extension
00088                         return false;
00089                 }
00090 
00091                 if ( in_array( $extension, array( 'php', 'php5' ) ) ) {
00092                         // Script extension, OK
00093                         return false;
00094                 }
00095                 if ( in_array( $extension, $extWhitelist ) ) {
00096                         // Whitelisted extension
00097                         return false;
00098                 }
00099 
00100                 if ( !preg_match( '/^[a-zA-Z0-9_-]+$/', $extension ) ) {
00101                         // Non-alphanumeric extension, unlikely to be registered.
00102                         //
00103                         // The regex above is known to match all registered file extensions
00104                         // in a default Windows XP installation. It's important to allow
00105                         // extensions with ampersands and percent signs, since that reduces
00106                         // the number of false positives substantially.
00107                         return false;
00108                 }
00109 
00110                 // Possibly bad extension
00111                 return true;
00112         }
00113 
00121         public static function fixUrlForIE6( $url, $extWhitelist = array() ) {
00122                 $questionPos = strpos( $url, '?' );
00123                 if ( $questionPos === false ) {
00124                         $beforeQuery = $url . '?';
00125                         $query = '';
00126                 } elseif ( $questionPos === strlen( $url ) - 1 ) {
00127                         $beforeQuery = $url;
00128                         $query = '';
00129                 } else {
00130                         $beforeQuery = substr( $url, 0, $questionPos + 1 );
00131                         $query = substr( $url, $questionPos + 1 );
00132                 }
00133 
00134                 // Multiple question marks cause problems. Encode the second and
00135                 // subsequent question mark.
00136                 $query = str_replace( '?', '%3E', $query );
00137                 // Append an invalid path character so that IE6 won't see the end of the
00138                 // query string as an extension
00139                 $query .= '&*';
00140                 // Put the URL back together
00141                 $url = $beforeQuery . $query;
00142                 if ( self::isUrlExtensionBad( $url, $extWhitelist ) ) {
00143                         // Avoid a redirect loop
00144                         return false;
00145                 }
00146                 return $url;
00147         }
00148 
00173         public static function findIE6Extension( $url ) {
00174                 $pos = 0;
00175                 $hashPos = strpos( $url, '#' );
00176                 if ( $hashPos !== false ) {
00177                         $urlLength = $hashPos;
00178                 } else {
00179                         $urlLength = strlen( $url );
00180                 }
00181                 $remainingLength = $urlLength;
00182                 while ( $remainingLength > 0 ) {
00183                         // Skip ahead to the next dot
00184                         $pos += strcspn( $url, '.', $pos, $remainingLength );
00185                         if ( $pos >= $urlLength ) {
00186                                 // End of string, we're done
00187                                 return false;
00188                         }
00189 
00190                         // We found a dot. Skip past it
00191                         $pos++;
00192                         $remainingLength = $urlLength - $pos;
00193 
00194                         // Check for illegal characters in our prospective extension,
00195                         // or for another dot
00196                         $nextPos = $pos + strcspn( $url, "<>\\\"/:|?*.", $pos, $remainingLength );
00197                         if ( $nextPos >= $urlLength ) {
00198                                 // No illegal character or next dot
00199                                 // We have our extension
00200                                 return substr( $url, $pos, $urlLength - $pos );
00201                         }
00202                         if ( $url[$nextPos] === '?' ) {
00203                                 // We've found a legal extension followed by a question mark
00204                                 // If the extension is NOT exe, dll or cgi, return it
00205                                 $extension = substr( $url, $pos, $nextPos - $pos );
00206                                 if ( strcasecmp( $extension, 'exe' ) && strcasecmp( $extension, 'dll' ) &&
00207                                         strcasecmp( $extension, 'cgi' ) )
00208                                 {
00209                                         return $extension;
00210                                 }
00211                                 // Else continue looking
00212                         }
00213                         // We found an illegal character or another dot
00214                         // Skip to that character and continue the loop
00215                         $pos = $nextPos;
00216                         $remainingLength = $urlLength - $pos;
00217                 }
00218                 return false;
00219         }
00220 
00239         public static function haveUndecodedRequestUri( $serverSoftware ) {
00240                 static $whitelist = array(
00241                         'Apache',
00242                         'Zeus',
00243                         'LiteSpeed' );
00244                 if ( preg_match( '/^(.*?)($|\/| )/', $serverSoftware, $m ) ) {
00245                         return in_array( $m[1], $whitelist );
00246                 } else {
00247                         return false;
00248                 }
00249         }
00250 
00251 }