首页 > 解决方案 > ZF3 向会话验证器添加可信代理时出现问题

问题描述

我在 MS Azure 上托管 Zend Framework 3 站点。会话验证存在问题,因为 Azure 的应用程序网关充当远程地址验证器不喜欢的反向代理,因此不会读取会话。

我可以从远程地址的类引用中看到 setTrustedProxies() ,根据文档,我可以将一个 IP 地址数组传递给该方法。但是,我真的不知道如何做到这一点。

我在 global.php 中配置 session_manager

'session_manager' => [
        // Session validators (used for security).
        'validators' => [
            RemoteAddr::class,
            HttpUserAgent::class,
        ],

    ],

然后,在 Module.php 中,我正在使用实例化会话管理器

$sessionManager = $serviceManager->get(SessionManager::class);

然后,我尝试使用以下带有假 IP 的受信任代理

$sessionManager = $serviceManager->get(SessionManager::class);
$request        = $serviceManager->get('Request');
$remAdd = $request->getServer()->get('REMOTE_ADDR');
$remoteAddr = new RemoteAdddress($remAdd);
$remoteAddr->setTrustedProxies(['192.98.98.11', '187.2.2.10']);
$remoteAddr->setProxyHeader('X-Forwarded-For');
$remoteAddr->setUseProxy($useProxy = true);
$chain   = $sessionManager->getValidatorChain();
$chain->attach('session.validate', array($remoteAddr, 'isValid'));

我几乎可以肯定这不是正确的方法,但我在网上找不到任何关于设置受信任代理的文档。

如果我做

$chain   = $sessionManager->getValidatorChain();
print_r($chain);

添加代理后,我在输出中看不到对代理的任何引用

Zend\Session\ValidatorChain Object
(
    [events:protected] => Array
        (
            [session.validate] => Array
                (
                    [1] => Array
                        (
                            [0] => Array
                                (
                                    [0] => Array
                                        (
                                            [0] => Zend\Session\Validator\RemoteAddr Object
                                                (
                                                    [data:protected] => 127.0.0.1
                                                )

                                            [1] => isValid
                                        )

                                )

                        )

                )

        )

    [eventPrototype:protected] => Zend\EventManager\Event Object
        (
            [name:protected] => 
            [target:protected] => 
            [params:protected] => Array
                (
                )

            [stopPropagation:protected] => 
        )

    [identifiers:protected] => Array
        (
        )

    [sharedManager:protected] => 
    [storage:protected] => Zend\Session\Storage\SessionArrayStorage Object
        (
        )

)

正如我所说,我很确定我会以错误的方式解决这个问题,因此非常感谢您在找到正确方法方面的任何帮助。

标签: zend-framework3

解决方案


我偶然发现了完全相同的问题,只是在我的情况下我使用的是 CF。

您的方法是错误的,因为您使用的是 Zend\Http\PhpEnvironment\RemoteAddress 并且您没有替换已加载的验证器 Zend\Session\Validator\RemoteAddr。

Zend\Session\Validator\RemoteAddr 在内部使用 Zend\Http\PhpEnvironment\RemoteAddress 所以你不应该使用 Zend\Http\PhpEnvironment\RemoteAddress:https ://github.com/zendframework/zend-session/blob/master/src/验证器/RemoteAddr.php

这是经过测试的工作代码:

public function onBootstrap(MvcEvent $event)
{
    $application = $event->getApplication();
    $serviceManager = $application->getServiceManager();

    // The following line instantiates the SessionManager and automatically
    // makes the SessionManager the 'default' one to avoid passing the 
    // session manager as a dependency to other models.
    $sessionManager = $serviceManager->get(SessionManager::class);

    $remoteAddr = new \Zend\Session\Validator\RemoteAddr();
    //$remoteAddr->setTrustedProxies([]);
    $remoteAddr->setProxyHeader('CF-Connecting-IP');
    $remoteAddr->setUseProxy(true);


        $current_chain = $sessionManager->getValidatorChain(\Zend\Session\Validator\RemoteAddr::class);

        $current_chain->attach(
                'session.validate',
               [ new \Zend\Session\Validator\HttpUserAgent(), 'isValid' ]
        );

        $current_chain->attach(
                'session.validate',
                [ $remoteAddr, 'isValid' ] 
            );

        $sessionManager->start();

        Container::setDefaultManager($sessionManager);
    }

结果:

Zend\Session\ValidatorChain Object
(
    [events:protected] => Array
        (
            [session.validate] => Array
                (
                    [1] => Array
                        (
                            [0] => Array
                                (
                                    [0] => Array
                                        (
                                            [0] => Zend\Session\Validator\HttpUserAgent Object
                                                (
                                                    [data:protected] => Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
                                                )

                                            [1] => isValid
                                        )

                                    [1] => Array
                                        (
                                            [0] => Zend\Session\Validator\RemoteAddr Object
                                                (
                                                    [data:protected] => MY_REAL_IP
                                                )

                                            [1] => isValid
                                        )
                                )
                        )
                )
        )
)

我还添加了print_r($remoteAddress); https://github.com/zendframework/zend-session/blob/master/src/Validator/RemoteAddr.php函数内并使用 TrustedProxies 进行测试:

/**
 * Returns client IP address.
 *
 * @return string IP address.
 */
protected function getIpAddress()
{
    $remoteAddress = new RemoteAddress();
    $remoteAddress->setUseProxy(static::$useProxy);
    $remoteAddress->setTrustedProxies(static::$trustedProxies);
    $remoteAddress->setProxyHeader(static::$proxyHeader);

    print_r($remoteAddress);

    return $remoteAddress->getIpAddress();
}

结果:

Zend\Http\PhpEnvironment\RemoteAddress Object
(
    [useProxy:protected] => 1
    [trustedProxies:protected] => Array
        (
            [0] => 192.98.98.11
            [1] => 187.2.2.10
        )

    [proxyHeader:protected] => HTTP_CF_CONNECTING_IP
)

结论是 setTrustedProxies 正在工作,你只是看不到它,因为https://github.com/zendframework/zend-session/blob/master/src/Validator/RemoteAddr.php没有返回它,因为它是可见的只需将它传递给 Zend\Http\PhpEnvironment\RemoteAddress。

您当然可以像您的代码一样覆盖“默认” SessionManager:

$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config);
$sessionManager = new SessionManager($sessionConfig);

但这只是可选的。


推荐阅读