Because form autocomplete temporarily disables clean URLs, this unexpected behavior can cause sites to lose tagging and author autocompletion capabilities if they rely on clean URLs for the autocomplete path to work, such as sites that have an index.html file or that redirect '/' from https to http. Ensuring that index.php is part of the explicit path in this case resolves these issues.
Background
Autocomplete fields throw the follow error:
An AJAX HTTP error occurred.
HTTP Result Code: 200
Debugging information follows.
Path: http://website/?q=eng/taxonomy/autocomplete/...
Autocomplete was working perfectly before upgrading to Drupal core 7.39 and chaos tools 1.8.
After some debugging the error is caused by the path set:
http://website/?q=eng/taxonomy/autocomplete/
This works if index.html doesn't exist, as it would be read by index.php automatically (even when a 301 http status message would be throw and then a redirect to http://website/eng/taxonomy/autocomplete/.. ).
To make it work with the index.html present on the site, I had to remove the '?q=' from the path.
This could be done updating the variable db.uri in misc/autocomplete.js (line 300).
But I opted to do it before the javascript on the includes/form.inc (line 4013), simply added $attributes['value'] = str_replace("?q=", "", $attributes['value']);
This is a temporal fix until the change from the Drupal core affecting the $variables['element'] ['#autocomplete_input']['#url_value'] is tracked down.
UPDATE
After tracking down the path the culprit is the function form_process_autocomplete, as this function is forcing to use non-clean urls. Return a non clean url when index.html exist causes the issue.
A lot of sites use index.html as splash page, and less frequent but there are sites that have other pages at the same level of the Drupal install. so the server index is not necessarily index.php. The server DirectoryIndex can be set to any type of document, (not only index.php or index.html - more info refer to: https://httpd.apache.org/docs/2.4/mod/mod_dir.html ).
The solution is to use index.php in the autocomplete path, it stills working using non-clean urls and it won't matter the server DirectoryIndex option set.
| Comment | File | Size | Author |
|---|---|---|---|
| #80 | autocomplete-security-optional-2599326-80.patch | 2.35 KB | pounard |
| #17 | autocomplete-clean-url-2599326-16.patch | 2.04 KB | David_Rothstein |
| #11 | autocomplete_function-2599326-11.patch | 1.73 KB | blanca.esqueda |
Comments
Comment #2
blanca.esqueda commentedComment #3
blanca.esqueda commentedAfter tracking down the path the culprit is the function form_process_autocomplete, as this function is forcing to use non-clean urls. Return a non clean url when index.html exist causes the issue.
Comment #4
blanca.esqueda commentedPlease review the patch attached.
A lot of sites use index.html as splash page, and less frequent but there are sites that have other pages at the same level of the Drupal install. So the server index not necessarily is index.php
I tested setting a condition to check if index.html was present and avoid the non-clean urls, and it worked.
But after thinking a bit more, the server DirectoryIndex can be set to any type of document, (not only index.php or index.html ).
refer to: https://httpd.apache.org/docs/2.4/mod/mod_dir.html
So the solution is to use index.php in the autocomplete path, this still working using non-clean urls and it won't matter the server DirectoryIndex option set.
Comment #6
blanca.esqueda commentedComment #10
blanca.esqueda commentedpatch status is failed because is not passing the profile.test
Message Group Filename Line Function Status
Autocomplete found. Other profile.test 352 ProfileTestAutocomplete->testAutocomplete()
the patch is checking for and url without index.php, so and update to the profileTestAutocomplete is necessary as well.
Comment #11
blanca.esqueda commentedUps... I forgot to include the new profileTestAutocomplete test.
Comment #13
blanca.esqueda commentedComment #14
blanca.esqueda commentedComment #15
cilefen commentedI have not ever heard of someone running Drupal like that.
I am moving this to "Normal" priority to signify a smaller scope because someone would have to place an index.html file in a Drupal installation for this to occur and that could cause other problems besides this one depending on the web server configuration. I argue that do to this is technically "hacking core" because a file has been placed in a Drupal core directory that doesn't belong.
Comment #16
blanca.esqueda commentedNot necessarily is hacking Drupal.
The government of Canada requires WetKit for their sites, and time ago it was an issue (and even recently) adding splash pages. So the index.html was a workaround.
( ie. https://github.com/wet-boew/wet-boew-drupal/issues/878 )
I agree it is a small scope, but it is still a bug. And a big one for that small scope because all the autocomplete fields stopped working and generate ajax errors.
I have't seen index.html causing other problems, beside Drupal works base on index.php so adding index.php to the autocomplete path would only make sure that it is pointing to the correct place. The autocomplete url path is used as absolute ( url($element['#autocomplete_path'], array('absolute' => TRUE)); ), and an absolute path should be a full path and contain the file it is pointing to.
Comment #17
David_Rothstein commentedYeah, this is a pretty unusual setup. Normally it's the responsibility of the site itself to handle these situations (see documentation of the 'script' option in url()) but I can see the argument that we should take care of it here since this is being run on sites that don't use non-clean URLs otherwise.
We should just use the 'script' option to do this, though, I think. See attached.
Comment #18
blanca.esqueda commentedThank you @David_Rothstein,
I wasn't aware of the script argument on the url function. everyday I learn something new!
I'm applying and testing right now your patch.
Comment #19
cilefen commentedThis is my standard cut-and-paste on the backport policy, it may apply here:
Please check if this is an issue with Drupal 8. If so, it must be fixed there first according to the backport policy. If it is, move it to branch 8.0.x-dev and tag it “Needs backport to D7”. There may also be an existing Drupal 8 issue. Try to find it. If one exists, tag it “Needs backport to D7”. If it is open, offer a patch. If its status is “Fixed”, make its status “Patch (to be ported)”, move it to version 7.x-dev and upload your latest patch if one exists.
Comment #20
blanca.esqueda commentedTested and it worked!
Applied the patch to a site using clean urls and to a site with non-clean urls, it fixed the issue in one and the other one continued working perfectly.
Comment #21
blanca.esqueda commented@cilefen thanks for the note. checking Drupal 8 right now.
Comment #22
natew commentedIf you are using the wetkit distribution: https://www.drupal.org/project/wetkit
There is a contrib module (spashify) included for this. There was some discussion about this a couple years back on github for the distribution on how to implement a spash page.: https://github.com/wet-boew/wet-boew-drupal/issues/280
Comment #23
blanca.esqueda commentedThank you @natew, I previously read that post and more other regarding the wetkit distribution and splash page.
But as @David_Rothstein commented:
There are sites that autocomplete stopped working and not all of them have a maintenance team to handle changes. If this was working on previous Drupal versions, there is not harm to make it work again if it requires a small code update only.
Comment #24
David_Rothstein commentedRegarding Drupal 8, I think this issue probably isn't relevant there since most of the autocomplete security fix from Drupal 7.39 didn't need to be applied to Drupal 8 (see #2554221: Port Cross-site Scripting - Autocomplete system from SA-CORE-2015-003 to Drupal 8).
Comment #25
blanca.esqueda commented@David_Rothstein, i didnt find either the autocomplete functions on drupal8 includes/form.inc
Also I tried to find if the same override clean-url was used somewhere else and I wasn't able to find it.
I checked directly the autocomplete path from an autocomplete field on drupal8 and the path is relative. The ?q= is not being assigned.
Same as you I don't think this would apply for Drupal8.
I think this would apply only to Drupal7.
Comment #26
mlncn commentedWe ran into this same issue on a site configured to redirect the home page, "/", to http but to otherwise leave well enough alone. (It redirects user, contact, subscribe, node/add and other form-containing paths to https.) So when taxonomy or user (author) autocomplete ignores clean URLs, the form redirects the slash-starting path (/?q=...) over to http and it fails as a security threat: "An AJAX HTTP error occurred. HTTP Result Code: 302 Debugging information follows. Path: https://example.org/?q=user/autocomplete StatusText: Found ResponseText: 302 Found Found The document has moved here. Apache/2.4.10 (Debian) Server at example.org Port 443"
While this can also be fixed by getting clever about redirect rule conditions that check for the query string, this patch will fix this problem also and i think that would be A Nice Thing. :-)
Comment #27
dinarcon commentedHi,
In a scenario like the one described by mlncn in #26, this patch solves the issue. Particularly, I have the node creation pages on HTTPS. The autocomplete provided by core was configured to post to https://portside.org/?q=taxonomy/autocomplete/field_name which was rewrote by the server to http://portside.org/?q=taxonomy/autocomplete/field_name Having the HTTPS page query an HTTP resource produced a mixed content error which effectively blocks the operation.
Even though I was able to apply the patch locally and it fixed the issue, my production environment is set up in a way in which I cannot modify Drupal's core files. So I was able to replicate the patch functionality using hook_url_outbound_alter() as follows:
Once this patch lands this hook implementation might not be needed. Meanwhile, if someone has a limitation that prevents patching core files, the previous hook implementation should do the trick.
Comment #28
David_Rothstein commentedCommitted to 7.x - thanks!
Comment #30
chellman commentedI ran into an issue with this fix that I want to document here. On a server running nginx, with direct access to the PHP files blocked, this fix breaks any link that doesn't use clean URLs. Allowing direct access to index.php fixes the issue using something like this in your nginx conf:
Comment #31
okolobaxa commentedProblem is still exists for me.
I use perusio nginx config (https://github.com/perusio/drupal-with-nginx) and Globalredirect module. On autocomplete ajax request is sended to url http://oldsaratov.ru/index.php?q=admin/views/ajax/autocomplete/taxonomy/... instead of http://oldsaratov.ru/admin/views/ajax/autocomplete/taxonomy/1/test
Is it problem nginx configuration, that block direct access to index.php ?
Comment #32
David_Rothstein commentedI assume you mean it breaks autocomplete URLs? (I don't see how the change in this issue could break links in general.)
I could put something in the release notes about this (or we could consider rolling it back in favor of a different solution) but I'm trying to understand the issue first... what is the use case for blocking direct access to Drupal's index.php file in the first place? That seems pretty unusual to me. Is it part of an attempt at denial-of-service protection at the Nginx level?
The original fix here was for an edge case also, but one that has some justification in the earlier comments.
Note that if you don't want to change your Nginx configuration, it should be possible to use hook_url_outbound_alter() in site-specific code to force the 'script' option to url() to always be empty - i.e. similar to what was discussed above (before this patch was committed) for forcing it to always be 'index.php', but essentially the opposite of that.
Comment #33
chellman commentedIn my case, yes, it was the autocomplete URLs, or anything else that would theoretically force index.php into the path.
Disallowing direct script access is a security feature of perusio's configs, which I also use:
https://github.com/perusio/drupal-with-nginx#security-features
I'm not enough of a security guy to know what the justification is, but I don't think it's crazy to expect index.php to work, so I personally don't think it's worth a rollback. I just wanted to document the issue in case anyone else noticed. Between a config change, or using hook_url_outbound_alter(), it should be fine.
Comment #34
omega8cc commentedNow this is a Drupal core bug / regression which has to be fixed in core. Not just popular Nginx configs, like BOA but Aegir forces clean URLs by default on all hosted sites, and Drupal core should be compatible with its own feature, and not just selectively "ignore" it.
[EDIT] I mean, if Drupal core provides clean URLs as a feature we can depend on, and we force clean URLs by default, plus we deny direct access to index.php, so we can properly filter all requests before they hit index.php as an internal location in Nginx, but core at some point decides to:
1. selectively ignore its own feature and force non-clean URLs selectively
2. then the "fix" for this weird method of fixing other problems assumes that index.php can be always hit directly
then we have a regression on top of another regression.
I couldn't consider this chain of "fixes" as "fixed".
Comment #35
lunk rat commentedThis needs attention. Autocomplete widget is broken in 7.42 for any site configured to force clean URLs or block direct access to index.php.
Comment #36
blanca.esqueda commentedAs commented by David_Rothstein:
This patch was needed, and resolved the autocomplete issue on more than one case (original issue, +comment #26). Functionality that was working before upgrade to Drupal 7.39.
But similar situation is happening for people running nginx were now they are the ones having issues on Drupal 7.42
Re-rolling back the patch is not a solution, so something that works for both cases should be worked out.
Note: the only thing that I don't get, it is how index.pho could be blocked to be access? Doesn't Drupal run using index.php?
Comment #37
David_Rothstein commented@omega8cc, Drupal core does not allow non-clean URLs to be disabled - they are always supposed to be functional. There are a couple other places in the codebase (for example here and other places in update.php) that assume that, and there's even a test for it.
But if you have an idea for another way to fix the autocomplete security issue (from https://www.drupal.org/SA-CORE-2015-003) that doesn't involve using non-clean URLs, it's definitely worth creating an issue for that.
Comment #38
David_Rothstein commentedWhat is the reason for denying access completely, rather than just intercepting the request and/or redirecting it?
In any case, for now I've added a note about this in the "Known issues" section of https://www.drupal.org/drupal-7.42-release-notes. Feel free to suggest any edits.
I think we should consider this issue fixed for now; I don't think we should roll this back unless there's a really compelling use case for blocking requests to index.php that I'm not understanding. But even so, definitely create a followup issue if there's a way to improve this.
Comment #39
omega8cc commented@David_Rothstein BOA and other popular Nginx configurations don't really "force" clean URLs in the way which could prevent them from working. These popular configurations used by thousands of live Drupal sites simply force
$conf['clean_url'] = 1;but non-clean URLs still work, as long as these requests don't *require* /index.php present in the URI.I have checked BOA configuration again, and in fact we have removed this restriction a long time ago, so
/index.php*can* be accessed directly, but we have arewriteredirect in place to automatically convert such requests toclean URLs,mainly for SEO purposes, extension-free URI, by popular demand.This
rewriteredirect makes your fix in this issue breaking things for BOA users. We don't need this fix, because BOA does recognize /index.php by default.I don't have any quick fix for this, so I guess we will revert this change in the D7 core used in BOA to prevent problems.
Again, I strongly disagree with the method of fixing problems for edge-case configurations (like with index.html instead of index.php recognized by default) by changes in core which break things potentially for everyone else.
Comment #40
blanca.esqueda commented@omega8cc
I don't consider the fix as edge-case... Similar as your situation, autocomplete was working perfectly before a Drupal version update.
In our case specifically before the 7.39 version, the changes was regarding a security issue. The non-clean autocomplete url was forced and broke things for some people.
I could say that a server configuration (like redirect in place to automatically convert request to extension-free) would be an edge-case as well.
And even I could quote you:
But as commented before I think the solution is to create a patch that works for everyone.
Before version 7.39, autocomplete was working for everyone.
So we know that not forcing a non-clean autocomplete url would resolve this issue for everyone, but it has security risks. So let's focus on find a way to mitigate that security risk when using clean urls.
I read that the security risk is that files were able to be added using the clean-url, so I'll play around and hopefully a solution that resolves everyones concerns could be found. If someone else is able to look for a solution as well, that would be great!
Comment #41
David_Rothstein commentedHm... then why is the patch that was committed here causing you a problem at all? It should work fine with a redirect like that.
What should happen is that Drupal requests
http://example.com/index.php?q=path/to/autocomplete, your nginx configuration redirects that tohttp://example.com/?q=path/to/autocomplete, and the server responds to that request.I don't have nginx handy to test this out, but I just tested a similar redirect rule for Apache (which I got from here):
The redirect happened as expected, and autocomplete worked fine.
Do you have any more information on why it isn't working?
Comment #42
omega8cc commented@Blanca.Esqueda It is a true, very edge case if Drupal site is not configured to recognize index.php by default, and instead uses some index.html by default. The subtle difference here is that BOA edge case didn't require patching core with any fix, while the edge case discussed here "required" it, although I would consider this to be a problem to be fixed on the server admin side and not in Drupal core.
@David_Rothstein Not really sure why, but reverting the patch from this issue resolved the problem for us, although it was only done to confirm that indeed this change in core broke things for BOA users. Furthermore, we can't force everyone to use our modified D7 core: https://github.com/omega8cc/7x and BOA users are free to use vanilla D7, so they would hit this problem anyway.
I think that the solution, at least for BOA and others who use similar Nginx configuration is to add an extra location for autocomplete above that redirect we have in place, so Nginx could ignore the redirect on autocomplete requests only. Something like:
Here we are using a trick to prevent matching the next location with fake error_page directive which sends the
redirectrequest to @drupal location, which then transfers the request to /index.php anyway, after some bot/crawler filtering.I will check now if this quick idea works in reality.
Comment #43
David_Rothstein commentedIt would definitely be great if someone has time to debug this and find out why. Like I said above, I can see why the patch in this issue would not work for a site that actually blocks index.php, but I can't see why it would fail for a site that just redirects index.php requests elsewhere... If that's not working, then it seems like something (either in core or in the nginx configuration) isn't working the way we think it is.
Comment #44
omega8cc commented@David_Rothstein -- Yes, it is rather weird, so I will debug this further and share the results here.
Comment #45
cafuego commentedFor the record, the snippet from #42 seems to do the trick for autocomplete.
Comment #46
cudevdev commentedOpened a new issue here: https://www.drupal.org/node/2671940
Comment #47
Anonymous (not verified) commentedI consider perusio nginx config to be the best out there and even if Nginx was not a mainstream http server when Drupal 7 came out it gained huge amounts of market share up until now and i think it should not be considered "edge case" to some http nerds. I really liked to have direct access to any .php file disabled with nginx.
On the other hand autocomplete was working perfectly over years with this kind of configuration. There is no warning or statement on the settings page of the "Clean URL" feature, that by enabling it Drupal will only use it partly as it was not the case. Is there any hope to see Drupal to go back into using clean URLs as it was before?
Comment #48
David_Rothstein commentedPer #38, I'm still looking for an explanation of why blocking index.php entirely (i.e. sending it to a 404 or 403) is a reasonable configuration Drupal should support.
But again, I definitely agree that redirecting index.php requests elsewhere (so "index.php" doesn't appear in the URL) is reasonable, so if autocomplete requests aren't working because of that we should fix it. #41 was my best attempt to debug that, and I couldn't figure out how to reproduce a problem.
Comment #49
David_Rothstein commentedAlso if it helps, here's more details on the code I suggested in #32 that can be used to undo the change from this issue at the Drupal level. If you put something like this in a custom module (and change "MYMODULE" to the name of the module) I think it should work. Based on some brief testing I just did now it seemed to.
Basically if for whatever reason you really want to try to ensure that Drupal itself never generates a link with "index.php" in it on your site, the above seems to me like the most robust way to do it.
Comment #50
David_Rothstein commentedAdding the issue from #46 as a related issue.
Comment #51
Anonymous (not verified) commentedThis is not about index.php file itself. This is more about the general fact that i can (and have) prevented access to any PHP file for security reasons. Perusio suggested this with a very simple (*.php) filter and it also blocks update.php and install.php as it does with any other PHP file. Additionall i have filters for *.txt files *.module, *.inc and so on. I want to make sure people only access those files i want them to access especially since Drupal mostly runs with lots of 3rd party modules with various files, coding and security standards. Nginx was designed to work this way (if you want to), why should i not use it if you want people (and search engines) to only read clean URLs anyway?
Comment #52
omega8cc commented@David_Rothstein -- after some testing it seems that there must be something else involved, like specific contrib module, which triggers the problem with broken autocomplete for some BOA / Nginx users, because in our tests with some popular distros, like Commerce Kickstart + vanilla D7 and our customized D7 we couldn't reproduce the problem, and there was no need to add that extra pseudo-location, plus the redirect to index.php-free URI works and doesn't break anything, so we are hunting some ghosts here, apparently.
@cafuego -- could you share more details on the exact URI path where #42 helps? As I have explained above, it gets a bit mysterious, because there must be something else which generates the problem and needs this fix, not just the change in the core.
I will report back if we will find reliable method to reproduce the problem.
Comment #53
Anonymous (not verified) commented#49, thanks! This is a much better workaround then patching core. At least for the time being.
Comment #54
David_Rothstein commented@omega8cc, thanks - that is useful info. So do we know if people who are experiencing the problem are experiencing it for a particular autocomplete on a particular form, or on all of them?
@sint, glad it was helpful. Regarding your earlier comment, blocking access to arbitrary .php files is definitely a reasonable thing to do... but usually when that's done there's a whitelist of particular .php files that are allowed to be accessed. So I would think the root-level Drupal index.php can/should be on that whitelist?
Comment #55
omega8cc commented@David_Rothstein -- I have asked those who reported the problem to provide more details on the paths/URIs/forms affected, because I believe they experienced the problem only on some forms -- otherwise we could easily reproduce the problem using the same D7 core with Commerce Kickstart, but we couldn't. Instead we have seen similar ajax pop-up errors, but not breaking anything, but it is probably separate issue.
As for blocking the direct access to /index.php by making it an "internal" location in Nginx, so it can be only accessed in the chain of internal requests, so effectively with aggressively forced clean URLs, we have tried that in the past, and I think the only reason was related to "security through obscurity" -- just to make it harder for bots to detect that the site is powered by PHP. But it broke things so we have removed the "internal" directive for /index.php because it doesn't provide anything important, besides some fancy "hardening".
Comment #56
cafuego commented@omega8cc -- The specific path our developers reported was on a username autocomplete field in a custom admin view: /?q=admin/views/ajax/autocomplete/user/%.
Comment #57
Anonymous (not verified) commented@David_Rothstein: If there is a reason to whitelist files, i would do so even if i don't like it. But with your provided hook, my Drupal sites are running fine again as it was for years without access to index.php.
@omega8cc: I don't do it for fancy hardening and it is pretty simple for anyone to figure out that a site is powered by Drupal. Most obvious thing are "sites/default/files" links. The reason i prevent "index.php?q=whatever" requests openly is because i don't want to have them as much as i don't want to have "/node/1" or "/nodes" openly. Why do people come up with modules like Global Redirect?
Comment #58
omega8cc commented@cafuego - Thank you, I will try this again.
@sint - Blocking direct access to /index.php (note, we are not talking about other php files here) has nothing to do with security, because there is no security difference / improvement between "index.php?q=whatever", "?q=whatever" and "whatever", other than URI elegance. You can achieve this elegance via rewrites/redirects as we do in BOA without making /index.php an "internal" location. You can filter anything you want before the request hits /index.php location, so making it internal does nothing useful. We have tried that config idiosyncrasies, but it only caused problems with zero benefit. There is just no point in making /index.php "internal" in Nginx.
Comment #59
cafuego commented@omega8cc - I should note that we did end up using error code 418 for the autocomplete redirect, as 405 was already used to deny access in case of non-GET/POST request methods.
Comment #61
gopisathya commented#49 solves our problem for the time being.
Comment #62
vadym.kononenko commented#49 works for me. Thank you.
Comment #63
cilefen commentedComment #64
thulenb commentedI am not much of a coder and do not know how to apply patches. Is this issue going to be solved with the next drupal core update?
Comment #65
norwegian.blue commentedUsing D7.43 & perusio 's nginx config I ran into this issue.
Tried #49 but I must have got the module wrong somehow as it broke.
#30 was a simple successful solution.
Is there any reason why one is better than the other?
Comment #66
mustanggb commented@nzpling:
#30 Exposes that your site is running on PHP to the outside world and allows the possibility of your site being accessed(/search engine indexed) with unclean URLs.
#49 Essentially undoes this undesirable change internally without hacking core and results in no changes as far as the outside world is concerned.
Depends on your preferences, personally I find #30 unacceptable, but it doesn't look like David_Rothstein is willing to revert this change to core behaviour, so take your pick.
Comment #67
thulenb commentedSo is the only way to get autocomplete funcionality run again to apply one of those patches? Isn't this functionality a very essential one and shouldn't it get fixed in Drupal Core?
Comment #68
David_Rothstein commentedIn what specific way did it break for you?
I don't think it does either of those things:
And again, if you really don't want "index.php" (or anything else you find undesirable) to appear in URLs, that should be easy to solve at the Nginx level by rewriting/redirecting the URLs rather than blocking them and that shouldn't interfere with autocomplete.
The best way is to fix the webserver to stop blocking URLs that Drupal relies on. If you don't run the webserver yourself, you could point whoever runs the server (or manages the Nginx configuration) to this issue.
If someone can come up with a reason why these Nginx configurations that block index.php are actually needed, or alternatively a way that Drupal core can work around the problem without reintroducing the problem this issue originally fixed or the security issue fixed in Drupal 7.39, I'm certainly willing to consider the idea of fixing this in core... But so far I don't think anyone has done that.
Comment #69
mustanggb commentedAnd where can the issue/patch that the security issue fixed be found, which vulnerability even was it?
Comment #70
David_Rothstein commentedUnfortunately since it's a security issue there's no public issue it was discussed in, but it's described in the "Cross-site Scripting - Autocomplete system" section of https://www.drupal.org/SA-CORE-2015-003, and the code can be found within http://cgit.drupalcode.org/drupal/commit/?h=7.x&id=be00a1ced4104d84df2f3... (basically the form_process_autocomplete() and misc/autocomplete.js parts of it).
Roughly speaking, without going into too much detail, the problem is described in this comment in form_process_autocomplete():
Basically before this change, by having user-supplied data appended to the end of a URL which Drupal made an Ajax request to, it was possible for a malicious user to trick the browser into making Ajax requests to a malicious file.
Switching to non-clean URLs was the most backwards-compatible way possible to get the user-supplied data into a query string instead (which protects against the browser being fooled).
Comment #71
mustanggb commentedI can't think why stripping the malicious pattern in autocomplete.js wouldn't be sufficient on it's own.
However if it's not would it not work to do something like:
At any rate it's pretty hard to come up with ideas without any repro steps.
Comment #72
norwegian.blue commented@David Rothstein
Called my module nginx_autocomplete_fix . (I'm a site builder more than developer, so haven't written modules from scratch before)
It rendered the content of the .module immediately below the body tag.:
/** * Implements hook_url_outbound_alter(). */ function nginx_autocomplete_fix_url_outbound_alter(&$path, &$options, $original_path) { if (isset($options['script']) && $options['script'] == 'index.php') { $options['script'] = ''; } }Of course it didn't fix the issue.
Comment #73
plazik commentedYou can add this code from #42 to drupal.conf.
Comment #74
David_Rothstein commentedPossibly, but I think what's in autocomplete.js is there more as a backup. I'm not sure it's possible to catch every file traversal method with that regular expression.
I think that would work but it would break essentially all autocomplete callbacks in core+contrib+custom modules and require them to be written differently, since they currently assume the data comes in via the menu system (e.g. it comes in via function parameters to https://api.drupal.org/api/drupal/modules!taxonomy!taxonomy.pages.inc/fu...).
One thing that maybe would work would be to make autocomplete.js verify URLs using a similar technique as ajax.js does (the latter was introduced in the same Drupal 7.39 security release). Then the request would no longer need to be made using unclean URLs since it is being verified via other methods instead. But that would be pretty involved.
Comment #75
David_Rothstein commentedJust a guess, but maybe you forgot to put a
<?phptag at the top of the .module file? (That could cause the server to not know it's PHP code, so maybe that's why it printed it to the page instead.)Comment #76
norwegian.blue commented@David_Rothstein
Doh !
Thanks. That was of course it!
I now have two working solutions.
Comment #77
cherner commentedIs anyone still having this issue?
I still get a 403 error for the autocomplete, I'm on 7.43 and using apache.
Comment #78
pounard@David_Rothstein We actually have no Drupal sites with index.php public, autocomplete is now broken on all of them. We never did have any problems running any site where q= is disallowed.
Our sysadmins completely disabled the non-clean URL because they are very difficult to parse and validate, leaving sites opened to all kinds of security problems, I don't know everything into details, but for example Apache would leave no way of correctly validating or cleaning the q= parameter, because using URL encoding within the parameter leaves the possibility to write the same thing an infinite different ways.
Comment #79
cherner commentedI actually found that "...q=" queries were being revoked in the apache config.
I removed this restriction, is it a huge security threat to allow access to index.php? Why does autocomplete now force non-clean URLs? I wonder if that will be changed back. The users need autocomplete to work to manage the content.
Comment #80
pounardWe actually won't expose index.php too, this is too much a security threat said our sysadmins, so I have made a patch that make this security measure optional, but on per default. We have other means to prevent the browser to hit a real file from autocomplete using nginx or apache configuration, and will use it instead.
Problem with the autocomplete security improvement in Drupal 7.39 is that it does break lots of our Drupal installations, or expose them to other security threats.
Please note this is not perfect and I do need to speak about this with our security team, but I do think I did understood the security issue (not completely though because it's not explained anywhere). I'm open too any criticism and like to find a way to make this more flexible, and better documented.
Comment #82
pounardTest failures are not related.
Comment #83
David_Rothstein commentedAllowing that to be bypassed sounds like it might be reasonable, but let's make a new issue for that instead. If it was broken by Drupal 7.39 then it really doesn't have much to do with this issue (since the patch here was committed in Drupal 7.42).
Comment #84
mustanggb commentedI've opened a new issue as requested: #2749007: Autocomplete broken for servers enforcing clean URLs
Comment #85
pounardThank you, sounds fair to open a new issue.
Comment #86
fortis commentedseems that i should create new one core patch if i will have directories at the drupal root such as: system/ and system/ajax because they will break drupal ajax
Comment #87
Konstantin Komelin commented@fortis You just reported a new core security issue ;) We are all in trouble
Comment #88
David_Rothstein commentedYes, if you put directories inside the Drupal docroot which conflict with paths defined by Drupal, you will break your site. Creating a top-level directory called "admin" would be another fun one :) I don't see what it has to do with this issue, though.... this was just about putting something like index.html there, which does not conflict.
The reference to a possible security issue sounds like a joke (which went over my head)... but if you seriously think there is a security issue with that for some reason, please report it to the Drupal Security Team rather than discussing it publicly here.
Comment #89
Tommy_001 commented#49 fixed the autocompletion problem on a nginx server. Thanks!
Comment #90
lamp5Confirm!
#49 fixed the autocompletion problem on a nginx server. Thanks!
Comment #91
W.M. commented#30 works for me with some little modifications that meet my fastcgi settings.
Comment #92
maxplus commentedHi,
Thanks!
#49 also solved my issue on my local MAC OSX dev environment (based on laravel/valet)
Comment #93
Chris CharltonThis ticket is marked as closed but the dialog here has been people trying a patch for D7. Did I miss something there?