MediaWiki  1.33.0
IEUrlExtension.php
Go to the documentation of this file.
1 <?php
62  public static function areServerVarsBad( $vars, $extWhitelist = [] ) {
63  // Check QUERY_STRING or REQUEST_URI
64  if ( isset( $vars['SERVER_SOFTWARE'] )
65  && isset( $vars['REQUEST_URI'] )
66  && self::haveUndecodedRequestUri( $vars['SERVER_SOFTWARE'] )
67  ) {
68  $urlPart = $vars['REQUEST_URI'];
69  } elseif ( isset( $vars['QUERY_STRING'] ) ) {
70  $urlPart = $vars['QUERY_STRING'];
71  } else {
72  $urlPart = '';
73  }
74 
75  if ( self::isUrlExtensionBad( $urlPart, $extWhitelist ) ) {
76  return true;
77  }
78 
79  // Some servers have PATH_INFO but not REQUEST_URI, so we check both
80  // to be on the safe side.
81  if ( isset( $vars['PATH_INFO'] )
82  && self::isUrlExtensionBad( $vars['PATH_INFO'], $extWhitelist )
83  ) {
84  return true;
85  }
86 
87  // All checks passed
88  return false;
89  }
90 
100  public static function isUrlExtensionBad( $urlPart, $extWhitelist = [] ) {
101  if ( strval( $urlPart ) === '' ) {
102  return false;
103  }
104 
105  $extension = self::findIE6Extension( $urlPart );
106  if ( strval( $extension ) === '' ) {
107  // No extension or empty extension
108  return false;
109  }
110 
111  if ( in_array( $extension, [ 'php', 'php5' ] ) ) {
112  // Script extension, OK
113  return false;
114  }
115  if ( in_array( $extension, $extWhitelist ) ) {
116  // Whitelisted extension
117  return false;
118  }
119 
120  if ( !preg_match( '/^[a-zA-Z0-9_-]+$/', $extension ) ) {
121  // Non-alphanumeric extension, unlikely to be registered.
122  // The regex above is known to match all registered file extensions
123  // in a default Windows XP installation. It's important to allow
124  // extensions with ampersands and percent signs, since that reduces
125  // the number of false positives substantially.
126  return false;
127  }
128 
129  // Possibly bad extension
130  return true;
131  }
132 
140  public static function fixUrlForIE6( $url, $extWhitelist = [] ) {
141  $questionPos = strpos( $url, '?' );
142  if ( $questionPos === false ) {
143  $beforeQuery = $url . '?';
144  $query = '';
145  } elseif ( $questionPos === strlen( $url ) - 1 ) {
146  $beforeQuery = $url;
147  $query = '';
148  } else {
149  $beforeQuery = substr( $url, 0, $questionPos + 1 );
150  $query = substr( $url, $questionPos + 1 );
151  }
152 
153  // Multiple question marks cause problems. Encode the second and
154  // subsequent question mark.
155  $query = str_replace( '?', '%3E', $query );
156  // Append an invalid path character so that IE6 won't see the end of the
157  // query string as an extension
158  $query .= '&*';
159  // Put the URL back together
160  $url = $beforeQuery . $query;
161  if ( self::isUrlExtensionBad( $url, $extWhitelist ) ) {
162  // Avoid a redirect loop
163  return false;
164  }
165  return $url;
166  }
167 
192  public static function findIE6Extension( $url ) {
193  $pos = 0;
194  $hashPos = strpos( $url, '#' );
195  if ( $hashPos !== false ) {
196  $urlLength = $hashPos;
197  } else {
198  $urlLength = strlen( $url );
199  }
200  $remainingLength = $urlLength;
201  while ( $remainingLength > 0 ) {
202  // Skip ahead to the next dot
203  $pos += strcspn( $url, '.', $pos, $remainingLength );
204  if ( $pos >= $urlLength ) {
205  // End of string, we're done
206  return false;
207  }
208 
209  // We found a dot. Skip past it
210  $pos++;
211  $remainingLength = $urlLength - $pos;
212 
213  // Check for illegal characters in our prospective extension,
214  // or for another dot
215  $nextPos = $pos + strcspn( $url, "<>\\\"/:|?*.", $pos, $remainingLength );
216  if ( $nextPos >= $urlLength ) {
217  // No illegal character or next dot
218  // We have our extension
219  return substr( $url, $pos, $urlLength - $pos );
220  }
221  if ( $url[$nextPos] === '?' ) {
222  // We've found a legal extension followed by a question mark
223  // If the extension is NOT exe, dll or cgi, return it
224  $extension = substr( $url, $pos, $nextPos - $pos );
225  if ( strcasecmp( $extension, 'exe' ) && strcasecmp( $extension, 'dll' ) &&
226  strcasecmp( $extension, 'cgi' )
227  ) {
228  return $extension;
229  }
230  // Else continue looking
231  }
232  // We found an illegal character or another dot
233  // Skip to that character and continue the loop
234  $pos = $nextPos;
235  $remainingLength = $urlLength - $pos;
236  }
237  return false;
238  }
239 
257  public static function haveUndecodedRequestUri( $serverSoftware ) {
258  static $whitelist = [
259  'Apache',
260  'Zeus',
261  'LiteSpeed' ];
262  if ( preg_match( '/^(.*?)($|\/| )/', $serverSoftware, $m ) ) {
263  return in_array( $m[1], $whitelist );
264  } else {
265  return false;
266  }
267  }
268 
269 }
IEUrlExtension\isUrlExtensionBad
static isUrlExtensionBad( $urlPart, $extWhitelist=[])
Given a right-hand portion of a URL, determine whether IE would detect a potentially harmful file ext...
Definition: IEUrlExtension.php:100
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
$query
null for the wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1588
$vars
static configuration should be added through ResourceLoaderGetConfigVars instead & $vars
Definition: hooks.txt:2220
IEUrlExtension\areServerVarsBad
static areServerVarsBad( $vars, $extWhitelist=[])
Check a subset of $_SERVER (or the whole of $_SERVER if you like) to see if it indicates that the req...
Definition: IEUrlExtension.php:62
IEUrlExtension\fixUrlForIE6
static fixUrlForIE6( $url, $extWhitelist=[])
Returns a variant of $url which will pass isUrlExtensionBad() but has the same GET parameters,...
Definition: IEUrlExtension.php:140
IEUrlExtension\haveUndecodedRequestUri
static haveUndecodedRequestUri( $serverSoftware)
When passed the value of $_SERVER['SERVER_SOFTWARE'], this function returns true if that server is kn...
Definition: IEUrlExtension.php:257
IEUrlExtension
Internet Explorer derives a cache filename from a URL, and then in certain circumstances,...
Definition: IEUrlExtension.php:44
IEUrlExtension\findIE6Extension
static findIE6Extension( $url)
Determine what extension IE6 will infer from a certain query string.
Definition: IEUrlExtension.php:192