Browse Source

made HTTP headers coming from proxies non-trusted by default

Fabien Potencier 14 years ago
parent
commit
932cd10477

+ 12 - 0
UPDATE.md

@@ -6,8 +6,20 @@ one. It only discusses changes that need to be done when using the "public"
 API of the framework. If you "hack" the core, you should probably follow the
 API of the framework. If you "hack" the core, you should probably follow the
 timeline closely anyway.
 timeline closely anyway.
 
 
+RC4 to RC5
+----------
+
+* To avoid security issues, HTTP headers coming from proxies are not trusted
+  anymore by default (like `HTTP_X_FORWARDED_FOR`, `X_FORWARDED_PROTO`, and
+  `X_FORWARDED_HOST`). If your application is behind a reverse proxy, add the
+  following configuration:
+
+        framework:
+            proxy: true
+
 RC3 to RC4
 RC3 to RC4
 ----------
 ----------
+
 * Annotation classes must be annotated with @Annotation 
 * Annotation classes must be annotated with @Annotation 
   (see the validator constraints for examples)
   (see the validator constraints for examples)
 
 

+ 1 - 0
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

@@ -47,6 +47,7 @@ class Configuration implements ConfigurationInterface
         $rootNode
         $rootNode
             ->children()
             ->children()
                 ->scalarNode('charset')->end()
                 ->scalarNode('charset')->end()
+                ->scalarNode('proxy')->defaultFalse()->end()
                 ->scalarNode('secret')->isRequired()->end()
                 ->scalarNode('secret')->isRequired()->end()
                 ->scalarNode('exception_controller')->defaultValue('Symfony\\Bundle\\FrameworkBundle\\Controller\\ExceptionController::showAction')->end()
                 ->scalarNode('exception_controller')->defaultValue('Symfony\\Bundle\\FrameworkBundle\\Controller\\ExceptionController::showAction')->end()
                 ->scalarNode('ide')->defaultNull()->end()
                 ->scalarNode('ide')->defaultNull()->end()

+ 2 - 0
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

@@ -66,6 +66,8 @@ class FrameworkExtension extends Extension
         $container->setParameter('kernel.secret', $config['secret']);
         $container->setParameter('kernel.secret', $config['secret']);
         $container->setParameter('exception_listener.controller', $config['exception_controller']);
         $container->setParameter('exception_listener.controller', $config['exception_controller']);
 
 
+        $container->setParameter('kernel.proxy', $config['proxy']);
+
         if (!empty($config['test'])) {
         if (!empty($config['test'])) {
             $loader->load('test.xml');
             $loader->load('test.xml');
         }
         }

+ 8 - 1
src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

@@ -24,7 +24,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CompilerDebugDum
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
 use Symfony\Component\DependencyInjection\Compiler\PassConfig;
 use Symfony\Component\DependencyInjection\Scope;
 use Symfony\Component\DependencyInjection\Scope;
-use Symfony\Component\HttpFoundation\File\File;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 
 
 /**
 /**
@@ -34,6 +34,13 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
  */
  */
 class FrameworkBundle extends Bundle
 class FrameworkBundle extends Bundle
 {
 {
+    public function boot()
+    {
+        if ($this->container->getParameter('kernel.proxy')) {
+            Request::trustProxyData();
+        }
+    }
+
     public function build(ContainerBuilder $container)
     public function build(ContainerBuilder $container)
     {
     {
         parent::build($container);
         parent::build($container);

+ 17 - 4
src/Symfony/Component/HttpFoundation/Request.php

@@ -20,6 +20,8 @@ use Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage;
  */
  */
 class Request
 class Request
 {
 {
+    static protected $trustProxy = false;
+
     /**
     /**
      * @var \Symfony\Component\HttpFoundation\ParameterBag
      * @var \Symfony\Component\HttpFoundation\ParameterBag
      */
      */
@@ -322,6 +324,17 @@ class Request
         $_REQUEST = array_merge($_GET, $_POST);
         $_REQUEST = array_merge($_GET, $_POST);
     }
     }
 
 
+    /**
+     * Trusts $_SERVER entries coming from proxies.
+     *
+     * You should only call this method if your application
+     * is hosted behind a reverse proxy that you manage.
+     */
+    static public function trustProxyData()
+    {
+        self::$trustProxy = true;
+    }
+
     /**
     /**
      * Gets a "parameter" value.
      * Gets a "parameter" value.
      *
      *
@@ -397,7 +410,7 @@ class Request
         if ($proxy) {
         if ($proxy) {
             if ($this->server->has('HTTP_CLIENT_IP')) {
             if ($this->server->has('HTTP_CLIENT_IP')) {
                 return $this->server->get('HTTP_CLIENT_IP');
                 return $this->server->get('HTTP_CLIENT_IP');
-            } elseif ($this->server->has('HTTP_X_FORWARDED_FOR')) {
+            } elseif (self::$trustProxy && $this->server->has('HTTP_X_FORWARDED_FOR')) {
                 return $this->server->get('HTTP_X_FORWARDED_FOR');
                 return $this->server->get('HTTP_X_FORWARDED_FOR');
             }
             }
         }
         }
@@ -600,9 +613,9 @@ class Request
         return (
         return (
             (strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
             (strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
             ||
             ||
-            (strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
+            (self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
             ||
             ||
-            (strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
+            (self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
         );
         );
     }
     }
 
 
@@ -613,7 +626,7 @@ class Request
      */
      */
     public function getHost()
     public function getHost()
     {
     {
-        if ($host = $this->headers->get('X_FORWARDED_HOST')) {
+        if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
             $elements = explode(',', $host);
             $elements = explode(',', $host);
 
 
             $host = trim($elements[count($elements) - 1]);
             $host = trim($elements[count($elements) - 1]);

+ 5 - 0
tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php

@@ -21,6 +21,11 @@ use Symfony\Component\HttpFoundation\Request;
 
 
 class RequestTest extends \PHPUnit_Framework_TestCase
 class RequestTest extends \PHPUnit_Framework_TestCase
 {
 {
+    public function setUp()
+    {
+        Request::trustProxyData();
+    }
+
     /**
     /**
      * @covers Symfony\Component\HttpFoundation\Request::__construct
      * @covers Symfony\Component\HttpFoundation\Request::__construct
      */
      */