소스 검색

made HTTP headers coming from proxies non-trusted by default

Fabien Potencier 14 년 전
부모
커밋
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
 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
 ----------
+
 * Annotation classes must be annotated with @Annotation 
   (see the validator constraints for examples)
 

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

@@ -47,6 +47,7 @@ class Configuration implements ConfigurationInterface
         $rootNode
             ->children()
                 ->scalarNode('charset')->end()
+                ->scalarNode('proxy')->defaultFalse()->end()
                 ->scalarNode('secret')->isRequired()->end()
                 ->scalarNode('exception_controller')->defaultValue('Symfony\\Bundle\\FrameworkBundle\\Controller\\ExceptionController::showAction')->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('exception_listener.controller', $config['exception_controller']);
 
+        $container->setParameter('kernel.proxy', $config['proxy']);
+
         if (!empty($config['test'])) {
             $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\Compiler\PassConfig;
 use Symfony\Component\DependencyInjection\Scope;
-use Symfony\Component\HttpFoundation\File\File;
+use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Bundle\Bundle;
 
 /**
@@ -34,6 +34,13 @@ use Symfony\Component\HttpKernel\Bundle\Bundle;
  */
 class FrameworkBundle extends Bundle
 {
+    public function boot()
+    {
+        if ($this->container->getParameter('kernel.proxy')) {
+            Request::trustProxyData();
+        }
+    }
+
     public function build(ContainerBuilder $container)
     {
         parent::build($container);

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

@@ -20,6 +20,8 @@ use Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage;
  */
 class Request
 {
+    static protected $trustProxy = false;
+
     /**
      * @var \Symfony\Component\HttpFoundation\ParameterBag
      */
@@ -322,6 +324,17 @@ class Request
         $_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.
      *
@@ -397,7 +410,7 @@ class Request
         if ($proxy) {
             if ($this->server->has('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');
             }
         }
@@ -600,9 +613,9 @@ class Request
         return (
             (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()
     {
-        if ($host = $this->headers->get('X_FORWARDED_HOST')) {
+        if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
             $elements = explode(',', $host);
 
             $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
 {
+    public function setUp()
+    {
+        Request::trustProxyData();
+    }
+
     /**
      * @covers Symfony\Component\HttpFoundation\Request::__construct
      */