如何配置Symfony才能让它在负载均衡和反向代理背后工作

3.4 版本
维护中的版本

当你部署程序时,可能会处在一个load balancer (如,一个AWS Elastic Load Balancer) 或一个反向代理 (如,缓存 时用的Varnish) 的后面。

多半而言,这不会对Symfony引发任何问题。但是,当通过代理传入请求时,特定的请求信息是由标准的 Forwarded 头或是特殊的非标 X-Forwarded-* 头来发送的。例如,若不读取 REMOTE_ADDR 头(它现在已是你的反向代理的IP地址),用户的真实IP将被存入一个标准的 Forwarded: for="..." 头或是一个非标准的 X-Forwarded-For 头。

如果你没有配置Symfony来寻找这些头,你会得到不正确的“客户端IP地址、客户端是否通过HTTPS来连接、正在请求的hostname和端口”等信息。

解决方案:trusted_proxies 

这没有问题 ,但你 确实 需要告诉Symfony“发生了什么”以及“哪个反向代理IP地址”将去做这一类事:

1
2
3
4
# app/config/config.yml
# ...
framework:
    trusted_proxies:  [192.0.0.1, 10.0.0.0/8]
1
2
3
4
5
6
7
8
9
10
11
12
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
                        http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
 
    <framework:config trusted-proxies="192.0.0.1, 10.0.0.0/8">
        <!-- ... -->
    </framework>
</container>
1
2
3
4
// app/config/config.php
$container->loadFromExtension('framework', array(
    'trusted_proxies' => array('192.0.0.1', '10.0.0.0/8'),
));

本例中,说你的(多个)反向代理有一个IP地址是 192.0.0.1 或者匹配了一个使用了CIDR notation 10.0.0.0/8 的IP地址范围。更多细节,参考 framework.trusted_proxies 选项。

另外还说你信任了“代理并没有发送冲突头”,如,在相同的请求中同时发送了 X-Forwarded-ForForwarded

就是这样!Symfony现在将寻找正确的头以获取诸如“客户端IP地址、host主机、端口,以及该请求是否使用了HTTPS”等信息。

但是我的反向代理IP持续在变怎么办! 

某些反向代理(如Amazon的Elastic Load Balancers)并没有静态IP地址,甚至没有你可以用CIDR注释来锁定的地址范围。这种情形,你需要 - 非常小心地 - 信任 全部 代理。

  1. 配置你的web服务器(集群)任何 load balancer以外的客户端进行响应。对于AWS来说,这可以通过 security groups来完成。

  2. 一旦你确保了流量仅能从你所信任的反向代理中获得,就要配置Symfony 始终 信任到来的请求。这可以在你的前端控制器中完成:

1
2
3
4
5
6
7
// web/app.php
 
// ...
Request::setTrustedProxies(array('127.0.0.1', $request->server->get('REMOTE_ADDR')));
 
$response = $kernel->handle($request);
// ...
  1. 确保你 app/config/config.yml 中的trusted_proxies选项没有设置,或令其覆写上例中的 setTrustedProxies() 调用 。

就是这样!防止流量来自所有的“非信任资源”,对你来说是超严苛的。如果你允许了外部流量,它们将 “欺诈模拟” 其真实IP地址为其他信息。

我的反向代理发送X-Forwarded-For但是并未过滤Forwarded头 

许多常用的代理程序,并不支持 Forwarded 头,而且默认时不过滤它。 理想情况是,你可以在自己的代理中配置它。万一无法实现,你应该告诉Symfony不要信任 Forwarded 头,但却仍然信任你自己代理的 X-Forwarded-For 头。

这可在前端控制器里完成:

1
2
3
4
5
6
7
// web/app.php
 
// ...
Request::setTrustedHeaderName(Request::HEADER_FORWARDED, null);
 
$response = $kernel->handle($request);
// ...

配置代理服务器的信任(proxy server trust)非常重要,因为不这么做将允许恶意用户来"spoof"(欺诈模拟)他们的IP地址。

我的反向代理使用非标准(不是X-Forwarded)头 

虽然 RFC 7239 最近定义了一个标准的 Forwarded 头以暴露全部代理信息,多数反向代理还是把信息存入非标准的 X-Forwarded-* 头里。

但如果你的反向代理使用了其他非标准的头名称,你可以配置它们 (参考 "Trusting Proxies")。

实现此功能的代码应当出现在前端控制器中 (如 web/app.php)。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)