Chris@17: Chris@17: * Chris@17: * For the full copyright and license information, please view the LICENSE Chris@17: * file that was distributed with this source code. Chris@17: */ Chris@17: Chris@17: namespace Symfony\Component\HttpKernel\HttpCache; Chris@17: Chris@17: use Symfony\Component\HttpFoundation\IpUtils; Chris@17: use Symfony\Component\HttpFoundation\Request; Chris@17: use Symfony\Component\HttpFoundation\Response; Chris@17: use Symfony\Component\HttpKernel\HttpKernelInterface; Chris@17: Chris@17: /** Chris@17: * @author Nicolas Grekas Chris@17: * Chris@17: * @internal Chris@17: */ Chris@17: class SubRequestHandler Chris@17: { Chris@17: /** Chris@17: * @return Response Chris@17: */ Chris@17: public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch) Chris@17: { Chris@17: // save global state related to trusted headers and proxies Chris@17: $trustedProxies = Request::getTrustedProxies(); Chris@17: $trustedHeaderSet = Request::getTrustedHeaderSet(); Chris@17: if (\method_exists(Request::class, 'getTrustedHeaderName')) { Chris@17: Request::setTrustedProxies($trustedProxies, -1); Chris@17: $trustedHeaders = [ Chris@17: Request::HEADER_FORWARDED => Request::getTrustedHeaderName(Request::HEADER_FORWARDED, false), Chris@17: Request::HEADER_X_FORWARDED_FOR => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_FOR, false), Chris@17: Request::HEADER_X_FORWARDED_HOST => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_HOST, false), Chris@17: Request::HEADER_X_FORWARDED_PROTO => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PROTO, false), Chris@17: Request::HEADER_X_FORWARDED_PORT => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PORT, false), Chris@17: ]; Chris@17: Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); Chris@17: } else { Chris@17: $trustedHeaders = [ Chris@17: Request::HEADER_FORWARDED => 'FORWARDED', Chris@17: Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', Chris@17: Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', Chris@17: Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', Chris@17: Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', Chris@17: ]; Chris@17: } Chris@17: Chris@17: // remove untrusted values Chris@17: $remoteAddr = $request->server->get('REMOTE_ADDR'); Chris@17: if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) { Chris@17: foreach ($trustedHeaders as $key => $name) { Chris@17: if ($trustedHeaderSet & $key) { Chris@17: $request->headers->remove($name); Chris@17: $request->server->remove('HTTP_'.strtoupper(str_replace('-', '_', $name))); Chris@17: } Chris@17: } Chris@17: } Chris@17: Chris@17: // compute trusted values, taking any trusted proxies into account Chris@17: $trustedIps = []; Chris@17: $trustedValues = []; Chris@17: foreach (array_reverse($request->getClientIps()) as $ip) { Chris@17: $trustedIps[] = $ip; Chris@17: $trustedValues[] = sprintf('for="%s"', $ip); Chris@17: } Chris@17: if ($ip !== $remoteAddr) { Chris@17: $trustedIps[] = $remoteAddr; Chris@17: $trustedValues[] = sprintf('for="%s"', $remoteAddr); Chris@17: } Chris@17: Chris@17: // set trusted values, reusing as much as possible the global trusted settings Chris@17: if (Request::HEADER_FORWARDED & $trustedHeaderSet) { Chris@17: $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); Chris@17: $request->headers->set($name = $trustedHeaders[Request::HEADER_FORWARDED], $v = implode(', ', $trustedValues)); Chris@17: $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); Chris@17: } Chris@17: if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) { Chris@17: $request->headers->set($name = $trustedHeaders[Request::HEADER_X_FORWARDED_FOR], $v = implode(', ', $trustedIps)); Chris@17: $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); Chris@17: } elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) { Chris@17: Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR); Chris@17: $request->headers->set($name = $trustedHeaders[Request::HEADER_X_FORWARDED_FOR], $v = implode(', ', $trustedIps)); Chris@17: $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); Chris@17: } Chris@17: Chris@17: // fix the client IP address by setting it to 127.0.0.1, Chris@17: // which is the core responsibility of this method Chris@17: $request->server->set('REMOTE_ADDR', '127.0.0.1'); Chris@17: Chris@17: // ensure 127.0.0.1 is set as trusted proxy Chris@17: if (!IpUtils::checkIp('127.0.0.1', $trustedProxies)) { Chris@17: Request::setTrustedProxies(array_merge($trustedProxies, ['127.0.0.1']), Request::getTrustedHeaderSet()); Chris@17: } Chris@17: Chris@17: try { Chris@17: return $kernel->handle($request, $type, $catch); Chris@17: } finally { Chris@17: // restore global state Chris@17: Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); Chris@17: } Chris@17: } Chris@17: }