Problem/Motivation

DRUPAL-SA-CORE-2016-003 introduced a new url rewriting rule in which the HTTP_PROXY header is cleared in web.config:

       <rule name="Erase HTTP_PROXY" patternSyntax="Wildcard">
          <match url="*.*" />
          <serverVariables>
            <set name="HTTP_PROXY" value="" />
          </serverVariables>
          <action type="None" />
        </rule>

In order to allow the urlrewrite module (for security reasons!) to add/alter/remove server variables users are required to add a new configuration setting (either through the UI or in applicationHosts.config):

https://technet.microsoft.com/es-es/library/ee619775(v=ws.10).aspx

By introducing that change, all IIS deployments have broken in a way that is difficult to diagnose and fix.

The error the user is presented with is this one:

HTTP Error 500.50 URL Rewrite Module Error - The server variable "HTTP_PROXY" is not allowed to be set. Add the server variable name to the allowed server variable list.

I'm not sure this qualifies as critical, but considering that IIS is considered as a supported web server, and that drupal ships with a web.config, breaking all IIS installs sounds to me as critical....

https://www.drupal.org/docs/7/system-requirements/web-server

The issue here is that the complimentary setting (allowed server variable) cannot be added in the web.config file, it needs to be setup at the applicationHosts.config level:

https://forums.iis.net/t/1187303.aspx
http://stackoverflow.com/questions/35634361/where-should-allowedservervariables-tag-live-in-azure-website-applicationhost

A possible solution is to evaluate properly if the newly included rule is really necessary and remove it if not.

Proposed resolution

  • Do not enforce the Url Rewrite rule by default.
  • Warn the user in the status page (REQUIREMENT_ERROR) when running on a PHP version affected by the issue and the mitigation IIS rewrite rule is not enabled.

With these changes:

  1. Users running on safe PHP environments/setups will notice nothing.
  2. Sites that were broken by DRUPAL-SA-CORE-2016-003 will instead keep running with a security warning/error in all admin pages.
  3. New installs will be blocked with an error until they properly setup their environment or update the PHP runtime.

Remaining tasks

RTBC

User interface changes

New warning in status/install when user is running a PHP version affected by Httpoxy and the web.config has not been properly set up.

API changes

None

Data model changes

None

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

david_garcia created an issue. See original summary.

david_garcia’s picture

Issue summary: View changes
david_garcia’s picture

Issue summary: View changes
david_garcia’s picture

Issue summary: View changes
alexpott’s picture

All we did we implement Microsoft's advice see https://support.microsoft.com/en-us/kb/3179800 - if that advice doesn't work is that our fault?

david_garcia’s picture

@alexpott I am blaming no-one. I'm just saying this needs to be fixed or looked at. I'm looking into what the best solution is, will report when done.

david_garcia’s picture

Issue summary: View changes

Investigated this....

[...] do not use CGI on a server that is running IIS. CGI is a largely obsolete interface that is replaced by newer and more performance-related interfaces.

FastCGI does not use environment variables for client request headers and does not have this issue.

The microsoft article states that CGI applications are affected, not fastCGI. No one is using (or should even consider using) the old CGI for hosting applications on IIS.

But later on they say:

However for PHP, some applications may use PHPs getenv() function to retrieve environment variables. Even when PHP is not hosted inside a CGI process, it replicates the CGI behavior by injecting request header values into the set of data available to its getenv() function. If you use a PHP application that retrieves HTTP_PROXY in this manner [...]

So I setup a sample script and did some tests, and can confirm that HTTP_PROXY is NEVER set by PHP itself in any way.

echo 'server:'. $_SERVER['HTTP_PROXY'];
echo PHP_EOL;
echo 'getenv:'. getenv('HTTP_PROXY');
echo PHP_EOL;
echo 'server:'. $_SERVER['HTTP_PROXY'];

Running this script with and without sending a "Proxy" HTTP header will yield the same output:

server:
getenv:
server:

To test this easily, use fiddler to modify the request headers on the fly.

My conclusion is that IIS+FastCGI is not affected by this issue, and that the URL Rewrite rule should be removed.

david_garcia’s picture

Tested this with different PHP versions.

PHP >= 7 is not affected by this issue.

PHP < 7 DOES EXHIBIT THE PROBLEM. The script in #7 does populate HTTP_PROXY server variable when used in PHP < 7.

david_garcia’s picture

Status: Active » Needs review
FileSize
2.45 KB

Not a definitive patch, but this is how I would deal with the issue:

  • Disable the rewrite rule (commented) by default.
  • Issue a warning in the status page when PHP < 7 and the rewrite rule is disable.

This will not bother users with PHP >= 7 (where the issue does not exist) and will allow users with PHP < 7 to notice that they need to change some deployment setting instead of just breaking their sites.

Status: Needs review » Needs work

The last submitted patch, 9: iis-httpoxy-2783079.patch, failed testing.

The last submitted patch, 9: iis-httpoxy-2783079.patch, failed testing.

alexpott’s picture

The PHP version thing is just probably reflecting which builds you tested with the latest PHP release... 5.6.23 and 5.5.37 both HTTP poxy fixes ... so does 7.0.8... but all the previous versions are vulnerable.

david_garcia’s picture

The PHP version thing is just probably reflecting which builds you tested with the latest PHP release... 5.6.23 and 5.5.37 both HTTP poxy fixes ... so does 7.0.8... but all the previous versions are vulnerable.

Totallly right. Misssed out that they fixed this here:

https://bugs.php.net/bug.php?id=72573

Reading through the changelog it was fixed in 5.6.24, 5.5.38 and 7.0.9 releases.

alexpott’s picture

Weird the latest releases aren't on https://secure.php.net/releases/ hence my error.

david_garcia’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
2.7 KB

Update patch to only show warning when the user is running any of the affected PHP versions.

david_garcia’s picture

Fixed how some of the warnings and comments are written.

alexpott’s picture

@david_garcia I'm not sure this is critical tbh. If this breaks your webserver then you're probably not secure since I'd wager that many people using IIS are not on the latest PHP versions. In order to secure your webserver you have to configure your server correctly. IMO it would be critical if we continued to serve the site which with the current patch we'll continue to do. And if you think that the error given by IIS is not explicit enough that's a bug in IIS. To be honest the error looks pretty good.

Personally all I think we should do in this issue is an @todo to web.config and .htaccess to remove the http_poxy mitigations once the minimum version of Drupal is greater than 7.08. And perhaps we can add information about this to the security release notes.

david_garcia’s picture

If this breaks your webserver then you're probably not secure

That's wrong if you are running a safe PHP version.

In order to secure your webserver you have to configure your server correctly.

What was implemented here is a partial (as it required additional manual setup otherwise it breaks your server) workaround for a bug in PHP, not in Drupal.

The fact that your server does not have the HTTP_PROXY as an allowed header does not mean that it is "incorrectly configured". Indeed, this was the first time ever I had heard about that IIS Rewrite feature.

And if you think that the error given by IIS is not explicit enough that's a bug in IIS.

It is explicit, the issue is that this setting is a "rare" and hidden feature that no one uses. And it's there for security.

Personally all I think we should do in this issue is an @todo to web.config and .htaccess to remove the http_poxy mitigations once the minimum version of Drupal is greater than 7.08. And perhaps we can add information about this to the security release notes.

What about promoting REQUIREMENT_WARNING to REQUIREMENT_ERROR? That would prevent clean installs without being secured, and will properly warn current installs.

The current patch has exponentially increased the barrier of entry for IIS deployments. You basically get a broken Drupal out of the box without a complex and additional manual setup (which by the way is not required at all if you run any of the latest PHP versions). And I can confirm this as I am behind the www.drupalonwindows.com website. I've been flooded with e-mails from people wondering what is going on with the out-of-the-box broken Drupal.

remove the http_poxy mitigations once the minimum version of Drupal is greater than 7.08.

That's right, this is just a mitigation in the sense that as long as no code is relying on the HTTP_PROXY server variable (which has been already been fixed by Guzzle) there is no real exploitation case out there for Drupal 8 (if I'm right). I think it simply does not compensate the heavily increased barrier of entry for IIS users.

xjm’s picture

Version: 8.3.x-dev » 8.1.x-dev

This is introduced in 8.1.x, so moving there.

Fabianx’s picture

What I never got about HTTPoxy was that they said, that unsetting via PHP is not enough to be secure.

If I see both the getenv() and the $_SERVER to bogus values - if its set at all, I can break an application that depends on the HTTP_PROXY environment var, but 99% of sites would not use that.

Also looking at the PHP code it is enough to unset it / set it to something else.

So a "fix" in PHP would break those installations using an obscure environment var (instead of proper config), but I know of no system that does.

So maybe in addition to the requirement warning, we could just unset the proxy header AND the getenv() on affected PHP versions. (and possibly allow an override for it via a hidden setting)

After all they could be using some obscure nginx config or something else or whatever ...

--

OT: The part "do not even bother to fix this in PHP - you can't."

was the most panic-y thing I disliked about the HTTPoxy thingy, because that creates unnecessary FUD.

Of course you can, you just break your application for the case where that env var is set, but using env vars for configuring a proxy is "meh" anyway ...

So put it in a variable, putenv() it and override $_SERVER and call it a day ...

--

TL;DR: Lets make Drupal secure out of the box for HTTPoxy (on unsupported configurations and IIS) by unsetting both things (getenv, $_SERVER) if using an affected PHP version; allow to override it (for the 0.00001% edge case) and warn about it in requirements, so that broken sites know where to look.

If I had to guess exactly 0% Drupal 8 sites use the environment variable to configure a proxy for the application.

david_garcia’s picture

So put it in a variable, putenv() it and override $_SERVER and call it a day ...

      // Some mitigation on the PHP side.
      global $DSA_HTTP_PROXY;
      $DSA_HTTP_PROXY = $_SERVER["HTTP_PROXY"];
      putenv("HTTP_PROXY=0");
      unset($_SERVER["HTTP_PROXY"]);

This will only happen for users on IIS that are running an affected PHP version and the have not enabled the IIS rewrite rule in web.config

Behaviour for non IIS users remains intact with this patch.

alexpott’s picture

Status: Needs review » Needs work

@Fabianx see https://gist.github.com/alexpott/c3903713ac888b069b915975162dc718 - it gets quite complex to work this out - apache_setenv()... I wonder what the equivalent would be for IIS? nginx, etc...

+++ b/core/modules/system/system.install
@@ -832,6 +832,44 @@ function system_requirements($phase) {
+      // Some mitigation on the PHP side.
+      global $DSA_HTTP_PROXY;
+      $DSA_HTTP_PROXY = $_SERVER["HTTP_PROXY"];
+      putenv("HTTP_PROXY=0");
+      unset($_SERVER["HTTP_PROXY"]);

This doesn't make sense to do in hook_install and also probably does not work.

david_garcia’s picture

This doesn't make sense to do in hook_install and also probably does not work.

Totally right... sometimes rushing produces awful results.

Lets make Drupal secure out of the box for HTTPoxy (on unsupported configurations and IIS)

Agreed. Unsetting the HTTP_PROXY environment variables will brake the same thing as the original DRUPAL-SA-CORE-2016-003 (anything depending on HTTP_PROXY would break), so we can harden this on the PHP side itself.

Yet, I am not sure how early in the request pipeline this should be placed. I've made an attempt, but not sure if this is the right place.

david_garcia’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 23: iis-httpoxy-2783079-23.patch, failed testing.

david_garcia’s picture

Rushing too much lately...

david_garcia’s picture

Status: Needs work » Needs review
alexpott’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -986,6 +989,18 @@ protected function initializeSettings(Request $request) {
+  protected function httpoxyMitigation(Request $request) {
+    putenv("HTTP_PROXY=0");
+    unset($_SERVER["HTTP_PROXY"]);
+  }

As detailed several times this is not enough. I think the patch is fine without the mitigation since setting up Guzzle to not use environment variables is already done by core and this is the only likely vulnerability. If contrib or custom set up Guzzle and do not use the D8 provided service then they are on their own. We could say this in the SA to cover our backs.

david_garcia’s picture

Status: Needs work » Needs review
FileSize
2.82 KB

Back to the patch in #16. I don't think there is really anything from the PHP side that will have a real impact on the issue.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

xjm’s picture

Issue tags: +Needs security review

Probably should also discuss how we mitigate (or don't) for IIS and older PHP versions with the sec team.

At a minimum, I think we need to update the SA with complete instructions for IIS (as well as maybe a pull request to httpoxy.org) and add this as a known issue in our release notes.

  1. +++ b/core/modules/system/system.install
    @@ -832,6 +832,39 @@ function system_requirements($phase) {
    +        'description' => t('Either update your PHP runtime version or uncomment the "Erase HTTP_PROXY" rule in your web.config file and add HTTP_PROXY to the allowed headers list to protect yourself against the Httpoxy vulnerability. See @url', ['@url' => 'https://www.drupal.org/node/2783079']),
    

    Isn't there a third option, something they can set in the IIS config?

    Also, we should not link issues in UI text. Instead, we should update the official SA and link that, or possibly https://support.microsoft.com/en-us/kb/3179800, with an accessible link text.

    Finally, I think the canonical form of the vulnerability name is all lowercase.

  2. +++ b/core/modules/system/system.install
    @@ -832,6 +832,39 @@ function system_requirements($phase) {
    +        'severity' => REQUIREMENT_WARNING,
    

    Should it be an error instead of a warning?

New sites will not be able to install until they fix it if we make it an error. Sites that are already installed are currently in a situation where they are broken, but protected. If we were to release this fix, they would start working again, but be vulnerable until they took additional mitigations. With it as an error, a message will be displayed on their admin pages, so they only know to mitigate it if they check the status report. Is that sufficient to mitigate the vulnerability when they update? Would it require a PSA?

david_garcia’s picture

Isn't there a third option, something they can set in the IIS config?

Not that I know about.

Also, we should not link issues in UI text. Instead, we should update the official SA and link that, or posibly https://support.microsoft.com/en-us/kb/3179800, with an accessible link text.

Patch now links to the SA (with an accessible link text).

Finally, I think the canonical form of the vulnerability name is all lowercase.

To my understanding Httpoxyy is a proper noun, and thus must be capitalized.

Should it be an error instead of a warning?

Latest patch boosts this to REQUIREMENT_ERROR.

alexpott’s picture

Status: Needs review » Needs work

For better or worse we should copy https://httpoxy.org/ and go lower case.

I like the solution of ensuring new installs have to address the issue before installing and existing sites still work but have a big warning.

david_garcia’s picture

Status: Needs work » Needs review
FileSize
2.88 KB

For better or worse we should copy https://httpoxy.org/ and go lower case.

Removed capitalization on usages of Httpoxy, really don't care about this picky detail but doing this because "that's what they do in other places" does not mean it is correct.

alexpott’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs security review

The patch looks good - @david_garcia, I agree with you "that's what they do in other places" is often a bad thing but in this case we are talking about a name. If I insisted that my name is "alex" and that I always wanted it to be lowercase - that would be okay - because it is my name and therefore my right to call myself what I like and insist of capitalisation I prefer. The namers of httpoxy have made a choice - whether we like their choice or disagree is immaterial.

From a security perspective making the web.config change optional but with an error on the status report if not implemented is better than the current situation where if the rule breaks your site you'd be tempted to remove the rule and not upgrade PHP. Also in core and anything that uses the http_client service is not vulnerable because of other, earlier, mitigations.

catch’s picture

+++ b/core/modules/system/system.install
@@ -832,6 +832,39 @@ function system_requirements($phase) {
+    if (!$httpoxy_rewrite) {
+      $requirements['iis_httpoxy_protection'] = [
+        'title' => t('IIS httpoxy protection'),
+        'value' => t('Your PHP runtime version is affected by the httpoxy vulnerability.'),
+        'description' => t('Either update your PHP runtime version or uncomment the "Erase HTTP_PROXY" rule in your web.config file and add HTTP_PROXY to the allowed headers list. See more details in the <a href=":link">security advisory</a>.', [':link' => 'https://www.drupal.org/SA-CORE-2016-003']),
+        'severity' => REQUIREMENT_ERROR,
+      ];

I'd be happier if this sent an e-mail (for example if update status is configured to send security e-mail notifications). We can't always guarantee that people see hook_requirements() messages so theoretically we're making a site less secure (if they updated core, fixed their IIS config to allow the header or already had it set, then updated again to this version).

However since core itself isn't vulnerable, it might be OK to leave it like this.

alexpott’s picture

To clarify why core in it's default configuration is not vulnerable. As part of the httpoxy mitigations added to core we initialize the http_client service using the values in \Drupal\Core\Http\ClientFactory::fromOptions():

      // Security consideration: prevent Guzzle from using environment variables
      // to configure the outbound proxy.
      'proxy' => [
        'http' => NULL,
        'https' => NULL,
        'no' => [],
      ]

The only way of telling Drupal to use an outbound proxy is to follow the example settings in default.settings.php:

/**
 * External access proxy settings:
 *
 * If your site must access the Internet via a web proxy then you can enter the
 * proxy settings here. Set the full URL of the proxy, including the port, in
 * variables:
 * - $settings['http_client_config']['proxy']['http']: The proxy URL for HTTP
 *   requests.
 * - $settings['http_client_config']['proxy']['https']: The proxy URL for HTTPS
 *   requests.
 * You can pass in the user name and password for basic authentication in the
 * URLs in these settings.
 *
 * You can also define an array of host names that can be accessed directly,
 * bypassing the proxy, in $settings['http_client_config']['proxy']['no'].
 */
# $settings['http_client_config']['proxy']['http'] = 'http://proxy_user:proxy_pass@example.com:8080';
# $settings['http_client_config']['proxy']['https'] = 'http://proxy_user:proxy_pass@example.com:8080';
# $settings['http_client_config']['proxy']['no'] = ['127.0.0.1', 'localhost'];

We used to say in default.settings.php that:

 * If these settings are not configured, the system environment variables
 * HTTP_PROXY, HTTPS_PROXY, and NO_PROXY on the web server will be used instead.

This is no longer true.

Maybe we should add some of this information to https://www.drupal.org/SA-CORE-2016-003?

catch’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

OK I don't love this, but given the original patch was hardening rather than closing an actual security issue, it seems like the least worst option.

Committed/pushed to 8.3.x, thanks!

Leaving at 'to be ported' for 8.2.x, and agreed it would be good to add more information to the SA. @david_garcia would you be up for drafting something (if you post it here, one of us could edit it in easily from that).

It would be good to get that up before cherry-picking to 8.2.x, but it'd also be good to get this patch into 8.2.0, so see how it goes.

  • catch committed fe1eb45 on 8.3.x
    Issue #2783079 by david_garcia, alexpott: DRUPAL-SA-CORE-2016-003...

  • catch committed e217f0d on 8.2.x
    Issue #2783079 by david_garcia, alexpott: DRUPAL-SA-CORE-2016-003...
catch’s picture

Status: Patch (to be ported) » Fixed

That's been quiet, so cherry-picked to 8.2.x, thanks!

Status: Fixed » Closed (fixed)

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