For MediaWiki (recent comments | status changes | tags | authors | states | release notes)
559 succeeded tests.
Index: trunk/phase3/includes/specials/SpecialUpload.php =================================================================== --- trunk/phase3/includes/specials/SpecialUpload.php (revision 56792) +++ trunk/phase3/includes/specials/SpecialUpload.php (revision 56793) @@ -59,9 +59,6 @@ # filename and description return; } - //if it was posted check for the token (no remote POST'ing with user credentials) - $token = $request->getVal( 'wpEditToken' ); - $this->mTokenOk = $wgUser->matchEditToken( $token ); # Placeholders for text injection by hooks (empty per default) $this->uploadFormTextTop = ""; @@ -73,13 +70,24 @@ $this->mCopyrightStatus = $request->getText( 'wpUploadCopyStatus' ); $this->mCopyrightSource = $request->getText( 'wpUploadSource' ); $this->mWatchthis = $request->getBool( 'wpWatchthis' ); - $this->mSourceType = $request->getText( 'wpSourceType' ); + $this->mSourceType = $request->getVal( 'wpSourceType', 'file' ); $this->mDestWarningAck = $request->getText( 'wpDestFileWarningAck' ); $this->mReUpload = $request->getCheck( 'wpReUpload' ); // retrying upload $this->mAction = $request->getVal( 'action' ); $this->mUpload = UploadBase::createFromRequest( $request ); + + // If it was posted check for the token (no remote POST'ing with user credentials) + $token = $request->getVal( 'wpEditToken' ); + if( $this->mSourceType == 'file' && $token == null ) { + // Skip token check for file uploads as that can't be faked via JS... + // Some client-side tools don't expect to need to send wpEditToken + // with their submissions, as that's new in 1.16. + $this->mTokenOk = true; + } else { + $this->mTokenOk = $wgUser->matchEditToken( $token ); + } } public function userCanExecute( $user ) {
Why can't file uploads be faked via JS?
With same-domain-policy *off* it seems like JS could POST uploads via session forgery.
If same-domain policy is off, you already have XSS, which is a strict superset of CSRF in terms of what it could do AFAICT. If you have XSS, you could create a hidden iframe to create the form, and scrape the edit token from it, so the token doesn't help in this case.
AFAICT, CSRF (for POSTs, let's say) is when you have a form on your site that looks like it submits to your site but actually submits to Wikipedia or whatever. For instance, a form asking you to enter a comment on the blog post, but really the form has action="[http://en.wikipedia.org/w/index.php?title=Special:Upload&action=submit http://en.wikipedia.org/w/index.php?title=Special:Upload&action=submit]", and the comment field has a meaningless name attribute that Wikipedia will ignore, and there are a bunch of hidden inputs like <input type=hidden name=wpUploadFile value="...appropriately encoded hello.jpg...">. Then the user submits the form and, if they're logged into Wikipedia, they just uploaded an evil image in a manner only traceable if you're logging Referers (and then only if they're sending them). But if there's a hidden token that's not guessable, this becomes impossible: you need XSS to scrape the token.
I don't understand why file uploads wouldn't be vulnerable to this.
Simetrical is essentially correct. File upload will be vulnerable to the cross site uploading with other persons credentials as described.
Although I don't think you can encode an upload via a form value attribute. But I think you can construct a XHR POST request with image data via javascript.
Even if the browser forbids XHR cross domain POST checks and does not enable form value attribute encoding... If you can get the user has to select an image the wikitext description could be changed without a token. (although the image won't be of the attackers choosing rather something the user thought they where contributing to a blog post )
With the editToken this is not so possible since you need XSS to scrape the token.
We should encourage Commonist and other upload bots to switch to the new upload api instead of submitting thing via the upload form. Maybe make notice that the wpToken will be enabled at X date to give them time to update their scripts?
Although I don't think you can encode an upload via a form value attribute.
Why not?
Even if the browser forbids XHR cross domain POST checks
Is there any browser that permits cross-domain XHR at all (without opt-in by the target)? See [http://www.w3.org/TR/XMLHttpRequest/#the-open-method the W3C spec]: "If the origin of url is not same origin with the XMLHttpRequest origin the user agent should raise a SECURITY_ERR exception and terminate these steps."
Content-Disposition: form-data; name="wpUploadFile"; filename="1Rosa-dos-ventos.JPG" Content-Type: image/jpeg ÿØÿàÿ (image data here)
instead of what you could generate with a web form:
Content-Disposition: form-data; name="wpUploadFile" ÿØÿàÿ (user attribute image data here)
And your right about the XHR POST I was thinking that file uploads could be mangled via javascript that way .. but can't recreate that locally or find documentation indicating its a problem.
At any-rate its a good idea to check the token for the last case described. (uploading an image to a compromised blog and having that redirect to a commons upload with your credentials )
"Although I don't think you can encode an upload via a form value attribute."
In theory you can't, in practice browser errors might allow it. See an older example for such an attack here: [http://kuza55.blogspot.com/2008/02/csrf-ing-file-upload-fields.html
So http://kuza55.blogspot.com/2008/02/csrf-ing-file-upload-fields.html
So] it's good practice to have layered security and protect against CSRF even in cases where it is not obviously necessary.
"AFAICT, CSRF (for POSTs, let's say) is when you have a form on your site that looks like it submits to your site but actually submits to Wikipedia or whatever."
Normally you can create the form by javascript and send it in a hidden iframe or something, the user doesn't need to initiate it or even notice there is a POST happening. That's not supposed to work for uploads as input type=file cannot be tampered with from javascript, but it's best to not rely on that.
How does the CSRF form select the source of the file upload?
I suppose it could be an upload form to WP that looks like it is local to the site.