macromindonline/laravel-proxy

为Laravel设置可信代理

3.3.4 2017-06-15 17:19 UTC

README

Build Status

Total Downloads

Laravel 5.5

可信代理现在包含在Laravel 5.5中。要配置此版本的Laravel,请参阅:https://laravel.net.cn/docs/5.5/requests#configuring-trusted-proxies

Laravel 5.0 - 5.4

对于Laravel版本5.0 - 5.4,请继续阅读以下内容。

新功能包括

  1. 可信代理现在设置为HTTP中间件,这比之前的ServiceProvider更合理。如果你不确定这是什么意思,请记住“Just Trust Fideloper™”。
  2. 你现在可以设置可信头名称。这对于不使用常用X-Forwarded-*头的代理很有用。有关示例和讨论,请参阅问题 #9问题 #7

要从Laravel 5项目目录运行以下命令以使用此功能

composer require fideloper/proxy

或者,当然,你可以直接编辑你的composer.json文件

{
    "require": {
        "fideloper/proxy": "^3.3"
    }
}

Laravel 4

你仍然可以使用此包的Laravel 4版本。请参阅此存储库的最新v2标签,它与Laravel 4版本兼容。

WAT

设置可信代理允许在代理后面正确生成URL、重定向、处理会话和记录日志。

如果你的Web服务器位于负载均衡器、HTTP缓存或其他中间代理(反向代理)后面,这很有用。

TL;DR 设置

安装可信代理

$ composer require fideloper/proxy

添加服务提供商

'providers' => array(
    # other providers omitted
    'Fideloper\Proxy\TrustedProxyServiceProvider',
);

将包配置文件发布到config/trustedproxy.php

$ php artisan vendor:publish --provider="Fideloper\Proxy\TrustedProxyServiceProvider"

在文件app/Http/Kernel.php中注册HTTP中间件

    protected $middleware = [
        // Illuminate middlewares omitted for brevity

        'Fideloper\Proxy\TrustProxies',

然后根据需要编辑已发布的配置文件config/trustedproxy.php

以下示例将信任IP地址为192.168.10.10的代理,例如负载均衡器或Web缓存

<?php

return [
    'proxies' => [
        '192.168.10.10',
    ],

    // These are defaults already set in the config:
    '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',
    ]
];

注意:如果你使用AWS Elastic Load Balancing或Heroku,FORWARDED和X_FORWARDED_HOST头应设置为null,因为目前不支持。

<?php

return [
    'proxies' => [
        '192.168.10.10',
    ],

    // These are defaults already set in the config:
    'headers' => [
        (defined('Illuminate\Http\Request::HEADER_FORWARDED') ? Illuminate\Http\Request::HEADER_FORWARDED : 'forwarded') => null,
        \Illuminate\Http\Request::HEADER_CLIENT_IP    => 'X_FORWARDED_FOR',
        \Illuminate\Http\Request::HEADER_CLIENT_HOST  => null,
        \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
        \Illuminate\Http\Request::HEADER_CLIENT_PORT  => 'X_FORWARDED_PORT',
    ]
];

这是做什么的?

如果你的网站位于负载均衡器、网关缓存或其他“反向代理”后面,每个Web请求都可能看起来总是来自那个代理,而不是客户端实际在网站上发起请求。

为了解决这个问题,此包允许你利用Symfony对代理的了解。关于“可信代理”的更多解释,请参阅以下内容。

稍长的安装说明

安装类似于Laravel 5包的典型安装

  1. 安装包
  2. 添加服务提供商
  3. 发布配置文件
  4. 添加中间件
  5. 配置你的可信代理

安装包

此包位于Packagist中,因此可以通过Composer轻松安装

方法一

$ composer require fideloper/proxy

方法二

{
    "require": {
        "fideloper/proxy": "^3.3"
    }
}

添加后,运行$ composer update以下载文件。

如果你想开发这个,你需要dev依赖项,你可以通过在composer require命令中添加--dev标志来获取这些依赖项。

添加服务提供商

安装的下一步是添加服务提供商。

编辑config/app.php并添加提供的Service Provider

'providers' => array(
    # other providers omitted
    Fideloper\Proxy\TrustedProxyServiceProvider::class,
);

发布配置文件

此包期望配置文件trustedproxy.php位于/config/trustedproxy.php。你可以通过使用新的Laravel 5 artisan命令复制包配置文件来完成此操作

$ php artisan vendor:publish --provider="Fideloper\Proxy\TrustedProxyServiceProvider"

完成之后,将有一个新的配置文件在config/trustedproxy.php中等待编辑。

注册中间件

编辑 app/Http/Kernel.php 并添加提供的中间件

    protected $middleware = [
        // Illuminate middlewares omitted for brevity

        'Fideloper\Proxy\TrustProxies',

配置受信任的代理

编辑新发布的 config/trustedproxy.php

<?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',
    ]
];

在上述示例中,我们假设我们有一个位于 192.168.1.10 的负载均衡器或其他代理。

注意:如果您使用Rackspace、Amazon AWS或其他PaaS“云”服务,这些服务提供负载均衡器,负载均衡器的IP地址可能未知。这意味着需要信任所有IP地址。

在这种情况下,可以将'proxies'变量设置为'*'

<?php

return [

     'proxies' => '*',

];

使用*将告诉Laravel信任所有IP地址作为代理。

但是,如果您处于以下情况,例如,您有一个内容分发网络(如Amazon CloudFront)将其传递给负载均衡器(如Amazon ELB),那么您可能最终会有一系列未知的代理从一端转发到另一端。在这种情况下,上面的'*'只会匹配最终的代理(在本例中是负载均衡器),这意味着调用$request->getClientIp()将返回下一行代理的IP地址(在本例中是内容分发网络的一个IP地址),而不是原始客户端IP地址。要始终获取原始客户端IP地址,您需要信任请求路由中的所有代理。您可以通过以下方式做到这一点

在这种情况下,可以将'proxies'变量设置为'':**

<?php

return [

     'proxies' => '**',

];

这将信任每个单独的IP地址。

更改X-Forwarded-*头名称

默认情况下,底层的Symfony Request类期望从代理发送以下头名称

  • X-Forwarded-For
  • X-Forwarded-Host
  • X-Forwarded-Proto
  • X-Forwarded-Port

某些代理可能会发送稍微不同的头。在这些情况下,您可以告诉Symfony Request类这些头的名称。

例如,HAProxy可能会发送一个X-Forwarded-Scheme头而不是X-Forwarded-Proto。我们可以通过以下配置调整Laravel(实际上是™,Symfony HTTP Request类)来修复这个问题

<?php

return [

    'headers' => [
        Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_SCHEME',
    ]

];

然后,我们的应用程序现在将知道如何处理X-Forwarded-Scheme头。

不用担心默认值是IN_THIS_FORMAT,而我们将头设置为In-This-Format。所有这些都在底层被规范化。Symfony的HTTP类是炸裂的 💥。

某些服务不支持特定的头,因此您也可以将这些设置为null以取消信任它们。特别是,AWS ELB和Heroku不支持FORWARDEDX_FORWARDED_HOST,因此您应该将它们设置为null以防止用户欺骗受信任的IP地址。

<?php

return [

    'headers' => [
        (defined('Illuminate\Http\Request::HEADER_FORWARDED') ? Illuminate\Http\Request::HEADER_FORWARDED : 'forwarded') => null,
        \Illuminate\Http\Request::HEADER_CLIENT_IP    => 'X_FORWARDED_FOR',
        \Illuminate\Http\Request::HEADER_CLIENT_HOST  => null,
        \Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
        \Illuminate\Http\Request::HEADER_CLIENT_PORT  => 'X_FORWARDED_PORT',
    ]

];

你知道CIDR吗,兄弟?

Symfony也接受用于配置受信任代理的CIDR 表示法。这意味着您可以设置受信任的代理为地址范围,如192.168.12.0/23

查看这里和这里以查看如何在Symfony中实现。

这有什么意义?

如果您的网站位于负载均衡器等代理后面,您的Web应用程序可能存在以下问题

  1. 重定向和PHP生成的URL可能在网址、协议和/或端口方面不准确。
  2. 可能不会为每个用户创建唯一的会话,从而导致可能访问错误的账户,或用户无法登录。
  3. 日志或其他数据收集过程的数据可能看起来来自一个位置(代理本身),您无法区分单个客户端的流量/操作。

我们可以通过监听 X-Forwarded-* 标头来绕过这些问题。这些标头通常由代理添加,以便您的Web应用程序了解请求发起者的详细信息。

常见的标头包括:

  • X-Forwarded-For - 客户端的IP地址
  • X-Forwarded-Host - 浏览器中用于访问网站的域名
  • X-Forwarded-Proto - 客户端使用的协议(http/https)
  • X-Forwarded-Port - 客户端使用的端口号(通常是80或443)

Laravel使用Symfony来处理请求和响应。这些类有处理代理的能力。然而,出于安全考虑,它们必须在尝试读取X-Forwarded-*标头之前知道哪些代理是“可信的”。

Laravel默认没有提供简单的配置选项来“信任”代理。此软件包仅提供一个选项。

Symfony和Laravel中的代理

为了使Laravel能够检查转发IP地址、协议和端口,我们需要告诉Laravel我们代理的IP地址,这样应用程序就知道要“信任”它们。如果它发现收到的IP地址是可信的IP地址,它将查找X-Forwarded-*标头。否则,它将忽略。

如果我们没有告诉Laravel我们的代理(或代理)的IP地址,它将出于安全考虑而忽略它。

按服务分类的IP地址

这个维基页面列出了流行的服务及其服务器IP地址(如果可用)。欢迎更新或建议!