ZF3 将可信代理添加到会话验证器时出现问题
ZF3 Problem adding trusted proxies to session validator
我正在 MS Azure 上托管 Zend Framework 3 站点。会话验证存在问题,因为 Azure 的应用程序网关充当远程地址验证器不喜欢的反向代理,因此不会读取会话。
我可以从远程地址的 class 参考中看到有一个方法 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
(
)
)
正如我所说,我很确定我正在以错误的方式进行此操作,因此非常感谢您帮助我找到正确的方法。
我偶然发现了完全相同的问题,只是我使用的是 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/Validator/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
)
)
)
)
)
)
我还在 https://github.com/zendframework/zend-session/blob/master/src/Validator/RemoteAddr.php 函数中添加了 print_r($remoteAddress); 并使用 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 没有 return 因为它只是将它传递给 Zend\Http\PhpEnvironment\RemoteAddress,所以它是可见的。 =18=]
您当然可以完全按照您的代码覆盖 'default' SessionManager:
$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config);
$sessionManager = new SessionManager($sessionConfig);
但这只是可选的。
我正在 MS Azure 上托管 Zend Framework 3 站点。会话验证存在问题,因为 Azure 的应用程序网关充当远程地址验证器不喜欢的反向代理,因此不会读取会话。
我可以从远程地址的 class 参考中看到有一个方法 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
(
)
)
正如我所说,我很确定我正在以错误的方式进行此操作,因此非常感谢您帮助我找到正确的方法。
我偶然发现了完全相同的问题,只是我使用的是 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/Validator/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
)
)
)
)
)
)
我还在 https://github.com/zendframework/zend-session/blob/master/src/Validator/RemoteAddr.php 函数中添加了 print_r($remoteAddress); 并使用 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 没有 return 因为它只是将它传递给 Zend\Http\PhpEnvironment\RemoteAddress,所以它是可见的。 =18=]
您当然可以完全按照您的代码覆盖 'default' SessionManager:
$sessionConfig = new SessionConfig();
$sessionConfig->setOptions($config);
$sessionManager = new SessionManager($sessionConfig);
但这只是可选的。