Laravel 5.5 现已包含 TrustedProxy
发布时间:作者: Paul Redmond
Laravel v5.5 刚在 Laracon EU 发布一周。您可能已经注意到 v5.5 的 composer.json 文件需要 fideloper/proxy composer 包。对我来说,这是我必须立即在每个项目中包含的那些包之一,因为我每天都使用 Amazon Web Services 和 Google Cloud,所以我感谢 Laravel 5.5 默认包含此包。
设置此包非常容易,我尤其感谢此包可以解决冗余设置问题。让我们简要介绍一下此包为 Laravel 提供的内容,以及为什么它是 Laravel 生态系统中重要的一个包。
TrustedProxy 包的作用是什么?
从高级的角度来看,Trusted Proxy 会告诉 Laravel 哪些代理可以信任,以及如何映射请求中的 X-Forwarded-*
标头。
包的自述文件可能更好地总结了这一点
设置可信代理允许在 Laravel 中进行正确的 URL 生成、重定向、会话处理和登录,即使是在代理后面。
如果您在负载均衡器、HTTP 缓存或其他中间(反向)代理后面使用您的 Web 服务器,这将非常有用。
…
Laravel 使用 Symfony 来处理请求和响应。这些类具有处理代理的方法。但是,出于安全原因,在它们尝试读取 X-Forwarded-* 标头之前,必须告知它们哪些代理是“可信的”。
Laravel 没有开箱即用的“信任”代理的简单配置选项。此包只是提供了一个选项。
使用代理
对于开发人员来说,使用像 Amazon Web Services 这样的云提供商和像 Cloudflare 这样的内容交付网络(CDN)来进行全站交付是司空见惯的事,应用程序位于这些服务后面,而不是直接暴露给世界。此外,您的应用程序甚至可能位于代理链后面。
例如,当您的网站或应用程序的 DNS 指向 CloudFlare 时,HTTP 请求将从 CloudFlare 代理到您的应用程序。
例如,您可能会注意到 Laravel 新闻的 HTTP 响应中有一些 CloudFlare 标头
$ curl -I https://news.laravel.net.cn/laravel-5-5HTTP/1.1 200 OKDate: Wed, 13 Sep 2017 04:15:50 GMTContent-Type: text/html; charset=UTF-8Connection: keep-aliveCache-Control: no-cacheServer: cloudflare-nginxCF-RAY: 39d849a3df7a39e2-PHX
您可以看到几个标头(例如 CF-RAY
和 Server
)在 cURL 响应中被发送回来。CloudFlare 将请求代理到实际的应用程序,获取响应,附加几个标头,然后将响应发送回最终用户。
由于 CloudFlare 在最终用户和应用程序之间进行代理,因此所有请求对于应用程序来说看起来都一样。为了让应用程序了解有关原始请求的重要详细信息,代理会发送 X-Forwarded*
标头。
以下是一些代理将发送的常用标头
-
X-Forwarded-For
– 定义原始 IP 地址的标准标头 (参考) -
X-Forwarded-Host
– 用于识别客户端在 Host HTTP 标头中请求的原始主机的事实上的标准标头 (参考) -
X-Forwarded-Proto
– 用于识别协议(如 HTTP 或 HTTPS)的事实上的标准标头 (参考) -
X-Forwarded-Port
– 帮助您识别客户端用于连接到负载均衡器的端口 (参考)
并非所有代理都使用事实上的标准标头,但此包可以帮助您映射这些标头,以便底层的 Symfony 请求对象知道如何信任代理并获取正确的值。
HTTPS -> HTTP
如果您在负载均衡器级别终止 TLS/SSL,您的应用程序可能会在内部接收 HTTP 请求,但实际上来自用户的原始请求是 HTTPS。如果您处于这种情况,您的应用程序将从代理接收类似于此的标头(以及其他标头)
X-Forwarded-Proto: https
TrustProxies 中间件通过调用 Symfony 的 HttpFoundation Request::setTrustedProxies()
方法,使 Request 对象自动了解代理标头,因此任何 PHP 生成的 URI 都将知道使用 HTTPS,即使请求是通过 HTTP 发出的。如果没有调用 setTrustedProxies()
,Laravel 应用程序将无法了解原始请求以及如何正确处理该请求。
配置
fideloper/proxy 包提供了以下 Laravel 配置,以便您能够调整包以适应各种设置,包括提供映射,如果您的代理使用非标准标头名称。
<?php return [ /* * Set trusted proxy IP addresses. * * Both IPv4 and IPv6 addresses are * supported, along with CIDR notation. * * The "*" character is syntactic sugar * within TrustedProxy to trust any proxy * that connects directly to your server, * a requirement when you cannot know the address * of your proxy (e.g. if using Rackspace balancers). * * The "**" character is syntactic sugar within * TrustedProxy to trust not just any proxy that * connects directly to your server, but also * proxies that connect to those proxies, and all * the way back until you reach the original source * IP. It will mean that $request->getClientIp() * always gets the originating client IP, no matter * how many proxies that client's request has * subsequently passed through. */ 'proxies' => [ '192.168.1.10', ], /* * Or, to trust all proxies that connect * directly to your server, uncomment this: */ # 'proxies' => '*', /* * Or, to trust ALL proxies, including those that * are in a chain of forwarding, uncomment this: */ # 'proxies' => '**', /* * Default Header Names * * Change these if the proxy does * not send the default header names. * * Note that headers such as X-Forwarded-For * are transformed to HTTP_X_FORWARDED_FOR format. * * The following are Symfony defaults, found in * \Symfony\Component\HttpFoundation\Request::$trustedHeaders * * You may optionally set headers to 'null' here if you'd like * for them to be considered untrusted instead. Ex: * * Illuminate\Http\Request::HEADER_CLIENT_HOST => null, * * WARNING: If you're using AWS Elastic Load Balancing or Heroku, * the FORWARDED and X_FORWARDED_HOST headers should be set to null * as they are currently unsupported there. */ 'headers' => [ (defined('Illuminate\Http\Request::HEADER_FORWARDED') ? Illuminate\Http\Request::HEADER_FORWARDED : 'forwarded') => 'FORWARDED', Illuminate\Http\Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', Illuminate\Http\Request::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', ]];
配置允许您定义要信任的 IP 地址,或者您可以信任所有直接代理,使用 *
,以及代理链中的任何代理,使用 **
。请仔细阅读文档,以及本文的最后一部分,了解如何锁定位于代理后面的应用程序。
您可以通过运行 vendor:publish
来创建 config/trustedproxy.php
配置。
php artisan vendor:publish --provider="Fideloper\Proxy\TrustedProxyServiceProvider"
在 Laravel 5.5 中,运行 vendor:publish
而不带参数将使用交互模式,这使得发布供应商文件变得更加容易。
了解更多
Symfony 有一篇简短的文章 如何在负载均衡器或反向代理后面配置 Symfony,其中包含一些有价值的信息。具体来说,以下安全注意事项在使用代理时至关重要
一些反向代理(如 Amazon 的 Elastic Load Balancers)没有静态 IP 地址,甚至没有可以使用 CIDR 表示法定位的范围。在这种情况下,您需要(非常谨慎地)信任所有代理。
- 配置您的 Web 服务器,使其不响应来自除负载均衡器以外的任何客户端的流量。对于 AWS,这可以通过安全组来完成。
- 一旦您保证流量只来自您信任的反向代理,请配置 Symfony 以始终信任传入请求。
查看 fideloper/proxy,其中包含一个关于如何设置 TrustProxies
中间件和配置的详细自述文件,其中包含大量关于此主题的信息。