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