symfony/symfony — pull request #8184 by dhotson (2013-06-03 14:11:45+00:00)
Title: [HttpFoundation] Request->getPort() should prefer HTTP_HOST over SERVER_PORT

| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | https://github.com/symfony/symfony/issues/3420
| License | MIT
| Doc PR | none

What is this?
----

This fixes the semantics of the `Request#getPort()` method to prefer the HTTP_HOST header over SERVER_PORT.

This is relevant in situations where the web server is running on a different port to the public facing website. e.g. load balancers, proxies, port forwarding.

Since the HTTP_HOST is user input it cannot be trusted. That's why I've introduced a `HostHeader` class to validate the value of HTTP_HOST according to [rfc3986](http://tools.ietf.org/html/rfc3986.html), which describes valid syntax for URIs.

The implementation builds a regular expression based on the grammar in the rfc, so the code may look a little bit gnarly. Feedback welcome. :)
On the plus side, it should be very strict about what it accepts.

Consistency
----

This change makes Symfony more consistent with other popular web frameworks.

Preferring HTTP_HOST over SERVER_NAME and SERVER_PORT is the strategy used by Ruby's Rack and Python's Django.

Python has a PEP that describes how to reconstruct URLs:
http://www.python.org/dev/peps/pep-0333/#url-reconstruction

https://github.com/rack/rack/blob/b6290a184cead2ffd731647d0836c5ebd3c21e7a/lib/rack/request.rb#L92

Additional security issues
----

Validating that the Host header is in a valid format isn't quite enough, you should also make sure the Host is something you expect it to be. Otherwise you can be vulnerable to attacks such as [cache poisoning via Host header injection](http://seclists.org/fulldisclosure/2008/Jun/169).

Django has a method to set allowed hosts:
https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts

Rails has some configuration to set the default url host:
http://edgeguides.rubyonrails.org/action_controller_overview.html#default-url-options

Symfony should probably adopt a similar approach to prevent these types of attacks.
This isn't a new issue though. I believe Symfony apps are already susceptible to this.