Skip to content

Commit

Permalink
API Fix HTTPS proxy header detection
Browse files Browse the repository at this point in the history
Didn't use the de facto standard HTTP_X_FORWARDED_PROTO or the less standard HTTP_FRONT_END_HTTPS.
Removed the 'X-Forwarded-Proto', since PHP should prefix/underscore all HTTP headers before it hits $_SERVER.

References:
- https://docs.djangoproject.com/en/1.4/ref/settings/#secure-proxy-ssl-header
- https://drupal.org/node/1859252
- https://drupal.org/node/313145
- http://scottwb.com/blog/2013/02/06/always-on-https-with-rails-behind-an-elb/
  • Loading branch information
chillu committed May 22, 2014
1 parent 6466e39 commit ec325a3
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 24 deletions.
46 changes: 27 additions & 19 deletions control/Director.php
Expand Up @@ -478,29 +478,37 @@ public static function protocol() {
* @return boolean
*/
public static function is_https() {
$return = false;
if ($protocol = Config::inst()->get('Director', 'alternate_protocol')) {
return $protocol == 'https';
}

if(isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
if(strtolower($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) == 'https') {
return true;
}
}

if(isset($_SERVER['X-Forwarded-Proto'])) {
if(strtolower($_SERVER['X-Forwarded-Proto']) == "https") {
return true;
}
}

if((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
return true;
$return = ($protocol == 'https');
} else if(
isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
) {
// Convention for (non-standard) proxy signaling a HTTPS forward,
// see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
$return = true;
} else if(
isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) == 'https'
) {
// Less conventional proxy header
$return = true;
} else if(
isset($_SERVER['HTTP_FRONT_END_HTTPS'])
&& strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) == 'on'
) {
// Microsoft proxy convention: https://support.microsoft.com/?kbID=307347
$return = true;
} else if((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
$return = true;
} else if(isset($_SERVER['SSL'])) {
return true;
$return = true;
} else {
$return = false;
}

return false;
return $return;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion control/HTTP.php
Expand Up @@ -377,7 +377,7 @@ public static function add_cache_headers($body = null) {
// By also using and etag that includes both the modification date and all the varies
// values which we also check against we can catch this and not return a 304
$etagParts = array(self::$modification_date, serialize($_COOKIE));
if (isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) $etagParts[] = $_SERVER['HTTP_X_FORWARDED_PROTOCOL'];
$etagParts[] = Director::is_https() ? 'https' : 'http';
if (isset($_SERVER['HTTP_USER_AGENT'])) $etagParts[] = $_SERVER['HTTP_USER_AGENT'];
if (isset($_SERVER['HTTP_ACCEPT'])) $etagParts[] = $_SERVER['HTTP_ACCEPT'];

Expand Down
28 changes: 24 additions & 4 deletions core/startup/ParameterConfirmationToken.php
Expand Up @@ -76,11 +76,31 @@ public function params() {
protected function currentAbsoluteURL() {
global $url;

// Are we http or https?
// Are we http or https? Replicates Director::is_https() without its dependencies/
$proto = 'http';

if(isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) {
if(strtolower($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) == 'https') $proto = 'https';
if(
isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
) {
// Convention for (non-standard) proxy signaling a HTTPS forward,
// see https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
$proto = 'https';
} else if(
isset($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTOCOL']) == 'https'
) {
// Less conventional proxy header
$proto = 'https';
} else if(
isset($_SERVER['HTTP_FRONT_END_HTTPS'])
&& strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) == 'on'
) {
// Microsoft proxy convention: https://support.microsoft.com/?kbID=307347
$proto = 'https';
} else if((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) {
$proto = 'https';
} else if(isset($_SERVER['SSL'])) {
$proto = 'https';
}

if((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')) $proto = 'https';
Expand Down
15 changes: 15 additions & 0 deletions tests/control/DirectorTest.php
Expand Up @@ -370,6 +370,21 @@ public function testIsHttps() {
$_SERVER['HTTP_X_FORWARDED_PROTOCOL'] = 'ftp';
$this->assertFalse(Director::is_https());

$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
$this->assertTrue(Director::is_https());

$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'http';
$this->assertFalse(Director::is_https());

$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'ftp';
$this->assertFalse(Director::is_https());

$_SERVER['HTTP_FRONT_END_HTTPS'] = 'On';
$this->assertTrue(Director::is_https());

$_SERVER['HTTP_FRONT_END_HTTPS'] = 'Off';
$this->assertFalse(Director::is_https());

// https via HTTPS
$_SERVER['HTTPS'] = 'true';
$this->assertTrue(Director::is_https());
Expand Down

0 comments on commit ec325a3

Please sign in to comment.