One of the many complications we didn't have time to solve when getting #538660: Move update manager upgrade process into new authorize.php file (and make it actually work) into core is the problem of http vs. https. One of the great things about the design we ended up with is that there's only a very small step in the process, visiting authorize.php, that requires the user to type their password for the workflow to proceed with elevated privileges. However, currently, we always just redirect to $base_url / authorize.php, which on 99% of sites is going to mean http. :(

It'd be really nice if there was a variable that determined if we should use https when we redirect to authorize.php.

It'd be even nicer if the installer auto-detected this somehow (ala the check for clean urls), and set this variable for you automatically.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

JacobSingh’s picture

There is the securepages module for this already and is kinda a glaring hole in core.

Perhaps we should add a general https detection and switch in core, and just apply that to authorize.php.

Here's what I'm thinking:
* A setting for https enabled / disabled
* A setting for which paths to use https for / which paths not to (like block module).
** This would default to /user/register, /user/login, authorize.php, /user/edit/*, /user/add

I suggest a follow-up issue to write a detection routine during install / on the settings page.

Code involved
* Making the settings page (duh - likely in system.module aka bloat.module)
* in url() so that we get the proper scheme. Perhaps add a 'scheme' option to the options passed into url() too.

Questions:

* Where does this setting go in the menus
* Redirect? Should we force users to use https on an https page?
* How much of this can we steal from Secure pages.

dww’s picture

Title: Provide a setting (and auto-discovery?) for if authorize.php can use https » Provide a setting (and auto-discovery?) for if authorize.php (and other relevant pages) can use https

@Jacob: Yes, exactly. If we're going to go through the trouble (and we should), then it should probably be a general solution, not specific to only solving this problem for authorize.php.

JacobSingh’s picture

You know, I think that securepages is actually pretty close to perfect for this. It does just what it promises and should be part of core IMO. It's a very low-level piece of functionality which adds zero overhead for non-users.

I don't feel like re-creating the wheel here. If it is too late to stuff this into D7, perhaps just tell users they should download and install one module insecurely, and that module is secure pages?

stella’s picture

I'd like to get this into Drupal 7 if we can. However, I know the securepages module has some issues with caching, and may need a bit of reworking - do we have the time to get it done? I'm not convinced, but then IMO it's a critical piece for authorize.php.

Gerhard Killesreiter’s picture

Issue tags: +Release blocker

Sending a SSH password over HTTP is most unreasonable. It controvenes the effort that has been made to add a secure way to update contribs to Core.

I would go as far as demanding that the SSH capability be removed if we can not make sure SSL is used. If SSL is not available, "update over SSH" should not be usable.

Dave Reid’s picture

Wait, we shouldn't be removing options if HTTPS isn't available, we should be (strongly?) warning. Not everyone has an SSL certificate or capability to have HTTPS on their server/host.

webchick’s picture

I have to say I'm really not eager to stick more functionality into D7 at this point that needs to be fully unit tested, bug-fixed, and polished. We need to be unit-testing, bug-fixing, and polishing the stuff that already got into Drupal 7 (which is already quite a lot). So even though I agree that from an architectural standpoint it'd be much better to have this be a generalized solution ala Secure Pages, and it'd be a wonderful core feature, it is a feature nonetheless, and we're past two feature freezes now for Drupal 7. :\ So unless Dries wants to come in and overrule me (which is fine), I don't think there's any way we can accept Secure Pages in core at this point. Sorry. :\

I do however totally agree with Gerhard that it's not acceptable to ship SSH support going through http and not https. I would ideally like to keep SSH support in, since it's an obvious glaring omission without. But I think we're going to have to do this with a one-off for authorize.php, given the point we are in the release cycle.

Setting a variable ala the way we do clean URL support (check to see if https://whatever is accessible, set a variable accordingly, and offer a settings page if someone wants to change it) seems the best way to solve this to me.

dww’s picture

Assigned: Unassigned » dww
Status: Active » Needs review
FileSize
2.97 KB

Wow, I didn't realize #1577: Mapping privilege separation on non-SSL/SSL had landed. ;) So, this is a lot closer than I thought. Here's a patch that should get us most of the way there... we use https for authorize.php if available, and we warn on authorize.php if we're still using http. I've only been able to test the http case right now, I was trying to get an https-enabled D7 test site up but I ran into some snags at my hosting provider. Don't have the energy to get it working on my laptop right now, either. ;)

killes@www.drop.org’s picture

Assigned: dww » Unassigned
Status: Needs review » Active
FileSize
3.47 KB

Patch looks ok, but I do not think that a simple warning is good enough, as I said above.

+++ includes/authorize.inc	26 Oct 2009 10:41:47 -0000
@@ -41,6 +42,10 @@ function authorize_filetransfer_form($fo
+    drupal_set_message(t('WARNING: you are not using an encrypted connection via https, so your password will be sent in plain text over the network.'), 'error');

I think this is not strong enough.

I've attached a modified patch that will disable SSH if somebody tries to use it over http.

This review is powered by Dreditor.

dww’s picture

Assigned: Unassigned » dww
Status: Active » Needs review

@killes: there are various reasons someone might actually want/need to use ssh over http. We discussed this at length in IRC. The FTP vs. SSH is more about what connection methods your server supports. The security of the localhost connection between httpd and the filesystem is pretty boring. What sucks is that your password is going in the clear over http, but that's sucky regardless of if it's an FTP or SSH connection. Hence the big red box. But in some cases that might be your only choice, or it might not matter (maybe you've got a VPN or something, or you're developing locally and don't want to run an ftpd on your laptop). I don't think we should be completely removing the SSH option just because we're over http. People who have SSH access and care about security but don't have https probably won't be using this tool anyway -- if you're comfortable with ssh and your shell, drush is probably a better solution. If they're not security conscious, we can't stop them from emailing their password to their friends, either. ;)

But yeah, I'm torn. I can definitely see the motive behind #9, and a large part of me agrees with it... Maybe the compromise is another non-UI variable that allows SSH over http, which can default to FALSE. But, in the few cases where it's actually okay, someone could add $conf['allow_ssh_authorization_over_http'] = TRUE; to their settings.php...

Regardless, I'm not sure why you set this to "active", we now have 2 viable patches to review. Nor why you unassigned me from this, since I'm trying to get a solution into core...

p.s. If we're not on https, maybe we should use JS to rot13 the password before we send it over the wire. ;) LOL

dww’s picture

Here's the compromise -- we unset the SSH option unless 'allow_ssh_authorization_over_http' is TRUE (defaults to FALSE).

So, there are 3 possible approaches when we're at authorize.php over http:

#8: Just warn about sending your password in clear text in all cases.

#9: If SSH is available, remove SSH as a choice and warn them we did so. If there's no SSH, just use the regular warning from #8.

#11: If SSH is available, and the setting is FALSE (the default) remove that option and warn them we did so. Otherwise, fall back to the regular warning from #8.

killes@www.drop.org’s picture

Not sure why these changes occurred.

While I am generally of the opinion to give people enough rope to hang themselves with, in the case of a website we need to consider that a compromised ssh account can also cause others to lose data. That being said, I'd be ok with providing an UI-less setting.

chx’s picture

Status: Needs review » Needs work

url('authorize.php', array('https' => TRUE)); on unclean URLs you will end up with ?q=authorize.php . You might need to deal with the globals similarly to what url() does with them.

instead of == FALSE just use !

chx’s picture

Support in URL for external HTTPS

=== modified file 'includes/common.inc'
--- includes/common.inc 2009-10-24 05:13:43 +0000
+++ includes/common.inc 2009-10-26 22:34:40 +0000
@@ -2411,6 +2411,14 @@ function url($path = NULL, array $option
     if ($options['query']) {
       $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . drupal_http_build_query($options['query']);
     }
+    if (isset($options['https']) && variable_get('https', FALSE)) {
+      if ($options['https'] === TRUE) {
+        $path = str_replace('http://', 'https://', $path);
+      }
+      elseif ($options['https'] === FALSE) {
+        $path = str_replace('https://', 'http://', $path);
+      }
+    }
     // Reassemble.
     return $path . $options['fragment'];
   }
chx’s picture

or (variable_get('https', FALSE) ? $base_secure_url : $base_url) . '/authorize.php'; is working too.

After some discussion on IRC we concluded to use url() because we sometimes need to pass in a query too.

JacobSingh’s picture

@killes I think I commented on it before, but if someone gets FTP, they can always post a new .bashrc and make you execute code next time you login. Or alias sudo :) Locking people out is not IMO a good strategy. I hate it when computers try to think for me too much. If I'm at home, and I want to use ssh on my localhost, do I give a sh*t about HTTPS?

I don't mind programs making it a pain, showing a warning, making me click on confirm box, etc, but cripling it because I should know better is annoying. Anyway, many people won't even have the SSH option as it is not commonly installed AFAIK.

-J

JacobSingh’s picture

@chx in #15

Shouldn't we be using scheme there instead of "https" in the $options[] array?

dww’s picture

Wow, our D7 https support is still quite broken. I've got a self-signed cert on my laptop now so I can actually play with this stuff. Running into all sorts of problems:

A) If you're admin'ing the site via http and then we redirect to https://example.com/authorize.php your SESSION doesn't persist since there's no secure session. #1577: Mapping privilege separation on non-SSL/SSL is 98% of the way there, and then balked at a friggin' checkbox to secure the login forms, so you actually still need a contrib module to secure your D7 site (unless you force the entire site to be https via apache). *sigh* So, to actually see this in action, you need the following in a module:

function wtf_form_alter(&$form, $form_state, $form_id) {
  switch ($form_id) {
    case 'user_pass':
    case 'user_login':
    case 'user_login_block':
    case 'user_register_form':
      $form['#https'] = TRUE;
      break;
  }
}

Once that's in place, if you login, core's magic ssid + sid session handling will kick-in, and then you'll actually be able to go back and forth between http and https pages and remain logged in.

B) url()'s handling of https is busted in various ways. First of all, the PHPDoc for the 'https' option says something sane, that if you don't define it, it defaults to leaving the scheme alone (so if you're on https you stay on https, or on http you stay on http). However, the code doesn't work like that, and if you don't define it, it forces https to be FALSE. :( Secondly, you can't set https = TRUE on an external link (which is what chx's cryptic comment in #14 actually means). ;)

C) Setting $form['#https'] causes FormAPI to call menu_path_is_external() which lives in menu.inc. However, this is a poorly named and placed function, since it doesn't actually have anything to do with the menu system at all. It's a 2-line helper function that just does some string comparison. In fact, it's 2 lines that are identically cut+pasted to/from url() (not sure which was first), although that's probably there for a performance optimization to avoid another function invocation inside the all-important url() function (I added a comment to that effect). Anyway, authorize.php hasn't needed to load menu.inc at all until now, and I refuse to load all of that in authorize.php for a 2-line URL helper function that FAPI now depends on. :( So, I moved menu_path_is_external() into common.inc (right below url(), in fact) with a comment that the function should be renamed to "url_is_external()" in D8. For now, I'm assuming we consider this too much of an API break at this point -- it's called by 2 other places in core besides menu.inc and form.inc. Here are all the call sites in core:

includes/form.inc:        !menu_path_is_external($element['#action'])) {
includes/menu.inc:  $item['external'] = (menu_path_is_external($item['link_path'])  || $item['link_path'] == '<front>') ? 1 : 0;
includes/menu.inc:  if ($path == '<front>' || menu_path_is_external($path)) {
modules/menu/menu.admin.inc:  if (!menu_path_is_external($item['link_path'])) {
modules/shortcut/shortcut.module:  return !menu_path_is_external($path) && menu_get_item($path);

I'd be happy to rename this, but not at the expense of a fight about the API freeze. For now, I'm okay just moving it into the right .inc file at least, even though the name is dumb.

Once all of that was fixed, this is now working. ;) Yay. Now all we need is the auto-detection during the installer (like clean URLs) and the UI for specifying what pages/forms you want to protect. That should probably happen as a separate issue, so long as it's a release-blocking critical task.

Sadly, this patch is going to conflict a bit with #610290: system_run_authorized() shouldn't always drupal_goto() so it can be used in submit handlers (I knew it would), but it'll be pretty easy to fix either patch once the other lands -- it's only going to be a minor conflict in system.module.

dww’s picture

Title: Provide a setting (and auto-discovery?) for if authorize.php (and other relevant pages) can use https » Force using https for authorize.php if available
Status: Needs work » Needs review

Forgot to fix status. Also, changing the title to explain what this issue is for. In terms of the UI in core to actually make https work, let's deal with that over at #616744: Add a UI for if the site supports https.

dww’s picture

Title: Force using https for authorize.php if available » Fix bugs in https support and force using https for authorize.php if available
Damien Tournoud’s picture

I cannot find anything wrong with this patch. The way we manage the HTTPS urls (not introduced by this patch) doesn't seem very elegant to me (especially the two new variables $base_secure_url and $base_insecure_url, and the way we have a $form['#https'] parameter separate from $form['#action']), but at least this patch improves things slightly.

I would argue renaming menu_path_is_external() to url_is_external() right away. This is not a commonly used function (I found 5 modules using it in the whole contrib repository), and the new name makes much more sense.

dww’s picture

For comparison, here's the same fixes but with just renaming menu_path_is_external() to url_is_external(). Yay for less @todo comments in core.

webchick’s picture

I was initially opposed to the name change for menu_path_is_external() to url_is_external(), but since we're forced to move it to common.inc, then I can't really justify not changing the name. But please try and get this patch finished up relatively quickly, because I really would like API freeze to mean something. :(

dww’s picture

So, we're having a big debate about the setting, the warnings, etc, in IRC right now, and I'm posting a few screenshots of the current, compromise approach when you visit authorize.php over http, with the setting both off (the default) or on. No warnings appear over https, obviously, so I'm not going to post screenies of those.

The original patch would basically always look like the "setting-on" version here.

In IRC, greggles proposed leaving ssh as an option in the select, but disabled with a note about it... sounds interesting. However, we still have the problem of the people who should be able to do ssh over http, so we'd probably still need the compromise setting.

dww’s picture

Attempted summary of the IRC chat:

- DamZ and davereid are opposed to trying to disable choices. We should always warn if you're sending any passwords over the wire, but otherwise, the admin should make the choice themselves. No setting, no special cases.

- greggles says that if we have the setting at all, people will just search, find the killswitch, and disable the checks if they want, so it doesn't actually help make it more secure.

- killes (of course) would prefer the ssh option completely removed on http no matter what, but is willing to live with the no-UI setting that allows this which defaults to FALSE.

- I point out that if we're going to have this setting and special-case handling of "secure" connection types, that really needs to be another attribute returned in the hook_filetransfer_backends() array. If someone adds an sftp backend, we need to be able to do whatever we're doing for that, too, not *just* ssh.

- greggles had suggested an alternative UI at one point. Instead of the "The SSH backend was disabled to protect the integrity of your password." text appearing in the warning message, we could leave the ssh choice in the drop-down, but have it be a disabled choice, and change the label to be something like: "SSH - disabled to protect your password, try https". Sounds like he's retracted that proposal, and now just supports a warning in all cases and no special handling at all -- just leave all the options there, but warn if they're on http.

From the KISS perspective, the just warn approach is obviously the least complicated.

Drat. I was really hoping we'd all agree on something, but greggles had to run, and I think killes might be sleeping by now. :( Not sure how to proceed...

Gerhard Killesreiter’s picture

Not sleeping yet, but I still think we should never allow a user to transmit the password for a service that was meant to be secure in cleartext.

Drupal is taking a rapidly increasing share of websites. We as the authors of Drupal thus have some responsibility towards the web at large. That's why we created a security team for example. It would contravene all this to allow people to send their server passwords over the wire unprotected. Some people will be stupid enough to use their root password.

As I said, I am generally willing to let people shoot themselves in the foot, but this case is special since any hijacked servers resulting from this can be used for a lot of nefarious purposes which would not only affect the owner of the server in question, but also the net at large.

moshe weitzman’s picture

Like DamZ, Reid, and greggles, I prefer a warning. Down with Drupal nanny. If people compromise own account then thats their problem. If a server or the Internet at large is so brittle that it does not expect those things to happen, then Drupal cannot save.

JacobSingh’s picture

Yeah, the fact is, this can keep going forever.

First it was "No ssh w/o HTTPS" then I pointed out that compromised FTP can be just as bad.

Now, "no passwords in plain text" Well, that's true, however Drupal hasn't had HTTPS support (and still doesn't) in core. So 90% of Drupal sites probably login to admin accounts (with PHP execution privilege) w/o encryption. If those got picked off on mod_cgi hosts, I could probably write outside of my webroot, replace .bashrc to trigger a trap on next SSH login and a tunnel. Or, if I can't access ~/ I'm pretty sure that I could mess w/ authorize.php to become a honey pot.

HTTPS is really important, BUT we cannot reserve "the good parts" of Drupal to people who don't have it. We absolutely should support it in core, we should have from Ver 1. Also, we should absolutely produce good educational materials for people, recommendations on getting a host with SSL, and warnings which link to these docs. Just locking people out of their systems is not the solution, but education and core support for SSL is.

-J

dww’s picture

There seems to be a growing majority supporting the approach of my original patch, so for the sake of argument, here's a reroll of #22 (including the rename to url_is_external() which webchick already agreed to) but with just the warning if you're on http, but all options are still available. No killswitch, no 'secure' attribute in the info hook, etc.

dww’s picture

p.s. Hopefully it doesn't matter and we don't try to special-case and restrict certain connection types, but the UI greggles proposed can't really be done until #284917: Allow FAPI select, radios, and checkboxes to specify some options as disabled is resolved, and that's blocked on IE stupidity, so it might never happen. So, if we do end up with some special handling for certainly connection types, we're just going to have to remove them from the list and add them to the warning text.

dww’s picture

JacobSingh’s picture

Patch looks good, but I didn't like the warning text much, wanted to put something which avoided technical language as much as possible and provided people a way to know what the problem is and what they can do about it.

Before:
Authorize file system changes | My Site

After:
Authorize file system changes | My Site

The link goes to http://drupal.org/http-information. I figure we can write this later.

dww’s picture

The link actually goes to http://drupal.org/https-information (which also doesn't exist). ;) Generally d.o has been trying to avoid the top-level URLs, but maybe for this it's okay. Fixed a few problems in the last patch:

- <a href="@https-link"> instead of <a href="@https-link"/> (that shouldn't try to be a self-closing tag).
- code style: no space between array and (
- Looks like the style for core are "Learn more" links, not "Learn more about this".

New message now reads:

WARNING: You are not using an encrypted connection, so your password will be sent in plain text. Learn more.

JacobSingh’s picture

Status: Needs review » Reviewed & tested by the community
webchick’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs documentation

I find myself conflicted about how protective we should be here. Gerhard makes a very compelling argument that I find myself strongly agreeing with, but the consensus from the security team seems to be that the warning is sufficient. We tried to get Heine to chime in here as a 'tie-breaker', but I think he's busy/away atm (last seen in #drupal 2+ weeks ago).

I'm also hesitant to commit this patch with the contents of http://drupal.org/https-information in the "I figure we can write this later." status. :P I'm also pretty sure that once I can track down add1sun, she will have a much more consistent path for this page than top-level http://drupal.org/https-information.

However, the rest of the patch looks solid. And since it introduces an API change, and I'm trying to get those all out of the queue so I can roll an unstable release soonish (maybe even today), and since changing the crippling-level of the warning and the documentation fixes could be follow-up patches that won't break anything else, I've committed this to HEAD.

Tagging "Needs documentation" and marking needs work. Would dww/JacobSingh/someone be able to summarize what that page needs to include so we could get some docs team rockstars working on this? Or better yet, write it? ;)

dww’s picture

API change documented in the module update doc: http://drupal.org/node/224333/revisions/view/763538/764780

No time for a full handbook page right now, but basic summary of what we need to say:

* sending your password in clear text over the wire is dangerous. https encrypts your connection between the browser and the server, http does not.

* how to setup https for your site:
server:
-- need a certificate (many hosting providers set these up for you, either automatically or for a fee)
-- need httpd configured properly (links to docs?)
drupal:
-- either force all connections to https via .htaccess redirect (more secure, but more expensive in terms of server load)
-- or set $conf['https'] = TRUE; in settings.php (less secure, see #575280: Impersonation when an https session exists., but at least your FTP/SSH password wouldn't be sent in plain text)

the Drupal parts are subject to change pending the outcome of #616744: Add a UI for if the site supports https and #575280 ...

JacobSingh’s picture

Status: Needs work » Needs review

I made a first go of this doc @ http://drupal.org/https-information. It's a WIP, as is HTTPS support, but a start.

Status: Needs review » Needs work

The last submitted patch failed testing.

catch’s picture

Priority: Critical » Normal
YK85’s picture

Hello,
I was wondering if Secure Pages module (http://drupal.org/project/securepages) will be needed in Drupal 7 with this feature in core?
Thanks!

grendzy’s picture

some discussion about the API name change over here:
#819844: url_is_external() is badly documented

jhodgdon’s picture

updating tagging scheme for update guide entries

jhodgdon’s picture

Status: Needs work » Fixed

Actually, it looks like this has been documented in the update 6/7 module guide
http://drupal.org/update/modules/6/7#url_is_external
as well as in the d.o documentation
http://drupal.org/https-information

So I think this is fixed.

junieMans’s picture

Status: Fixed » Needs review

#8: 607008-8.authorize_php_https.patch queued for re-testing.

catch’s picture

Status: Needs review » Fixed

Please don't request re-tests of fixed patches.

Status: Fixed » Closed (fixed)
Issue tags: -Security improvements, -Release blocker, -Update manager, -Needs documentation updates

Automatically closed -- issue fixed for 2 weeks with no activity.