MediaWiki
REL1_19
|
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 }