Page MenuHomePhabricator

api.php gives a 302 redirect to URL with '&*' appended, breaking CORS requests
Closed, ResolvedPublic

Description

On local and on http://mediawiki.org, uploading a file through MWMediaDialog provokes an unknown xhr error.

Calling the generated POST request to commons directly, the following error appears:
'origin' parameter does not match Origin header

Event Timeline

Restricted Application added subscribers: Steinsplitter, Aklapper. · View Herald TranscriptApr 13 2016, 6:25 PM
Restricted Application added a subscriber: Matanya. · View Herald TranscriptApr 13 2016, 6:43 PM
Esanders added a subscriber: Esanders.EditedApr 13 2016, 6:43 PM

I get the same on mw.org and en.wp

Just checked, this happens on enwiki as well, so it's probably been out there for a while now

Esanders triaged this task as High priority.Apr 13 2016, 6:45 PM
ferdbold updated the task description. (Show Details)Apr 13 2016, 6:46 PM

Calling the generated POST request directly, the following error appears:
'origin' parameter does not match Origin header

This is probably expected because you won't have the same headers anymore. I get the following console error though:

XMLHttpRequest cannot load https://commons.wikimedia.org/w/api.php?origin=https%3A%2F%2Fwww.mediawiki.org. Response for preflight is invalid (redirect)
matmarex renamed this task from Breaking error on uploading media to api.php gives a 302 redirect to URL with '&*' appended, breaking CORS requests.Apr 13 2016, 7:06 PM
hoo raised the priority of this task from High to Unbreak Now!.Apr 13 2016, 7:06 PM
Restricted Application added a subscriber: Urbanecm. · View Herald TranscriptApr 13 2016, 7:06 PM
hoo added a subscriber: hoo.Apr 13 2016, 7:07 PM

This also breaks changing sitelinks on Wikidata. This causes data inconsistencies between Wikidata and the clients (Wikipedias etc.).

This started around 17:45 UTC today, judging by when the cross-wiki uploads stopped happening: https://commons.wikimedia.org/w/index.php?title=Special:RecentChanges&tagfilter=cross-wiki-upload

$ curl -i https://commons.wikimedia.org/w/api.php?origin=https%3A%2F%2Fen.wikipedia.org
HTTP/1.1 302 Found
Date: Wed, 13 Apr 2016 19:09:31 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: mw1197.eqiad.wmnet
X-Powered-By: HHVM/3.12.1
X-Content-Type-Options: nosniff
Cache-control: no-cache
P3P: CP="This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info."
Location: https://commons.wikimedia.org/w/api.php?origin=https%3A%2F%2Fen.wikipedia.org&*
Backend-Timing: D=22416 t=1460574571343474
Vary: Accept-Encoding,X-Forwarded-Proto
X-Varnish: 2395388687, 1604903450, 440530922
Via: 1.1 varnish, 1.1 varnish, 1.1 varnish
Age: 0
X-Cache: cp1054 miss+chfp(0), cp3040 pass+chfp(0), cp3040 frontend pass+chfp(0)
Strict-Transport-Security: max-age=31536000
Set-Cookie: WMF-Last-Access=13-Apr-2016;Path=/;HttpOnly;Expires=Sun, 15 May 2016 12:00:00 GMT
X-Analytics: https=1;nocookies=1
X-Client-IP: 91.218.200.230
Set-Cookie: GeoIP=PL:77:Krak_w:49.92:20.20:v4; Path=/; secure; Domain=.wikimedia.org

<html>
<head>
<title>Security redirect</title>
</head>
<body>
<h1>Security redirect</h1>
<p>
We can't serve non-HTML content from the URL you have requested, because
Internet Explorer would interpret it as an incorrect and potentially dangerous
content type.</p>
<p>Instead, please use <a href="https://commons.wikimedia.org/w/api.php?origin=https%3A%2F%2Fen.wikipedia.org&amp;*">thi
s URL</a>, which is the same as the
URL you have requested, except that "&amp;*" is appended. This prevents Internet
Explorer from seeing a bogus file extension.
</p>
</body>
</html>

Worked around for now:

[19:23] <logmsgbot> !log ori@tin Synchronized php-1.27.0-wmf.20/includes/libs/IEUrlExtension.php: Live-hack IEUrlExtension::haveUndecodedRequestUri() to always return true (duration: 00m 33s)
[19:24] <logmsgbot> !log ori@tin Synchronized php-1.27.0-wmf.21/includes/libs/IEUrlExtension.php: Live-hack IEUrlExtension::haveUndecodedRequestUri() to always return true (duration: 00m 33s)
Andrew lowered the priority of this task from Unbreak Now! to High.Apr 13 2016, 9:05 PM

This was indirectly caused by https://gerrit.wikimedia.org/r/#/c/283230/. That patch resulted in a change to the value of SERVER_SOFTWARE variable, which confused MediaWiki's IEUrlExtension::areServerVarsBad() into using QUERY_STRING rather than REQUEST_URI when checking for file extensions in the URL. Apparently, QUERY_STRING is encoded/decoded incorrectly in WMF production (see T132629), which caused the file extension detection to give a false positive (or possibly the code was broken all along, but that seems unlikely to me).

Change 283341 had a related patch set uploaded (by Ori.livneh):
Force $_SERVER['SERVER_SOFTWARE'] to be "Apache"

https://gerrit.wikimedia.org/r/283341

Change 283341 merged by jenkins-bot:
Force $_SERVER['SERVER_SOFTWARE'] to be "Apache"

https://gerrit.wikimedia.org/r/283341

Anomie added a subscriber: Anomie.Apr 14 2016, 1:07 PM

Whether or not QUERY_STRING is encoded incorrectly, that doesn't look like the cause of your problem here. From P2895,

["QUERY_STRING"]=>
string(41) "oxrigin=https%3A%2F%2Fwww.mediawiki.org&*"
["REQUEST_URI"]=>
string(52) "/w/api.php?oxrigin=https%3A%2F%2Fwww.mediawiki.org&*"

The encoding in both variables matches.

Before the avoid-IE-stupidity redirect, those would have been

["QUERY_STRING"]=>
string(41) "oxrigin=https%3A%2F%2Fwww.mediawiki.org"
["REQUEST_URI"]=>
string(52) "/w/api.php?oxrigin=https%3A%2F%2Fwww.mediawiki.org"

In REQUEST_URI, IEUrlExtension::findIE6Extension() will see ".php?" in the middle of the string and return "php" as the extension, which is allowed and so results in no redirect. But in QUERY_STRING it sees only the ".org" at the end so it'll return "org" as the extension, which is not allowed. This is specifically noted as the intended behavior when it can't rely on REQUEST_URI accurately representing a request to "/w/api%2Ephp?..."

Hmm, okay, looks like I was mostly wrong then.

I think there's a bug in mw.ForeignApi JS code too, it should avoid producing URLs that trigger the IE extension check. mw.Api actually handles this for GET requests.

And I'd say there's another bug in WebRequest::checkUrlExtension(), there's probably no need to perform the check for OPTIONS requests (like the CORS pre-flight one that started this task). AFAIK it's impossible to navigate to a page with the OPTIONS method, it's only used for CORS AJAX.

Change 283487 had a related patch set uploaded (by Bartosz Dziewoński):
ForeignApi: Percent-encode dots in the 'origin' parameter

https://gerrit.wikimedia.org/r/283487

matmarex closed this task as Resolved.Apr 21 2016, 4:36 PM
matmarex assigned this task to ori.
matmarex removed a project: Patch-For-Review.

@ori fixed the Wikimedia configuration long ago. My patch above should prevent reoccurrence should the config be changed again.

Change 283487 merged by jenkins-bot:
mw.ForeignApi: Percent-encode dots in the 'origin' parameter

https://gerrit.wikimedia.org/r/283487