‪TYPO3CMS  9.5
ReferrerEnforcer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
26 
31 {
32  private const ‪TYPE_REFERRER_EMPTY = 1;
33  private const ‪TYPE_REFERRER_SAME_SITE = 2;
34  private const ‪TYPE_REFERRER_SAME_ORIGIN = 4;
35 
39  protected ‪$request;
40 
44  protected ‪$requestHost;
45 
49  protected ‪$requestDir;
50 
51  public function ‪__construct(ServerRequestInterface ‪$request)
52  {
53  $this->request = ‪$request;
54  $this->requestHost = rtrim($this->‪resolveRequestHost($request), '/') . '/';
55  $this->requestDir = $this->‪resolveRequestDir($request);
56  }
57 
58  public function ‪handle(array $options = null): ?ResponseInterface
59  {
60  $referrerType = $this->‪resolveReferrerType();
61  // valid referrer, no more actions required
62  if ($referrerType & self::TYPE_REFERRER_SAME_ORIGIN) {
63  return null;
64  }
65  $flags = $options['flags'] ?? [];
66  $expiration = $options['expiration'] ?? 5;
67  // referrer is missing and route requested to refresh
68  // (created HTML refresh to enforce having referrer)
69  if (($this->request->getQueryParams()['referrer-refresh'] ?? 0) <= time()
70  && (
71  in_array('refresh-always', $flags, true)
72  || ($referrerType & self::TYPE_REFERRER_EMPTY && in_array('refresh-empty', $flags, true))
73  || ($referrerType & self::TYPE_REFERRER_SAME_SITE && in_array('refresh-same-site', $flags, true))
74  )
75  ) {
76  $refreshUri = $this->request->getUri();
77  $refreshUri = $refreshUri->withQuery(
78  $refreshUri->getQuery() . '&referrer-refresh=' . (time() + $expiration)
79  );
80  $scriptUri = $this->‪resolveAbsoluteWebPath(
81  'EXT:core/Resources/Public/JavaScript/ReferrerRefresh.js'
82  );
83  return new ‪HtmlResponse(sprintf(
84  '<html>'
85  . '<head><link rel="icon" href="data:image/svg+xml,"></head>'
86  . '<body><a href="%1$s" id="referrer-refresh">&nbsp;</a>'
87  . '<script src="%2$s"></script></body>'
88  . '</html>',
89  htmlspecialchars((string)$refreshUri),
90  htmlspecialchars($scriptUri)
91  ));
92  }
93  $subject = $options['subject'] ?? '';
94  if ($referrerType & self::TYPE_REFERRER_EMPTY) {
95  // still empty referrer or invalid referrer, deny route invocation
96  throw new MissingReferrerException(
97  sprintf('Missing referrer%s', $subject !== '' ? ' for ' . $subject : ''),
98  1588095935
99  );
100  }
101  // referrer is given, but does not match current base URL
102  throw new InvalidReferrerException(
103  sprintf('Invalid referrer%s', $subject !== '' ? ' for ' . $subject : ''),
104  1588095936
105  );
106  }
107 
108  protected function ‪resolveAbsoluteWebPath(string $target): string
109  {
111  GeneralUtility::getFileAbsFileName($target)
112  );
113  }
114 
115  protected function ‪resolveReferrerType(): int
116  {
117  $referrer = $this->request->getServerParams()['HTTP_REFERER'] ?? '';
118  if ($referrer === '') {
120  }
121  if (strpos($referrer, $this->requestDir) === 0) {
122  // same-origin implies same-site
123  return self::TYPE_REFERRER_SAME_ORIGIN | ‪self::TYPE_REFERRER_SAME_SITE;
124  }
125  if (strpos($referrer, $this->requestHost) === 0) {
127  }
128  return 0;
129  }
130 
131  protected function ‪resolveRequestHost(ServerRequestInterface ‪$request): string
132  {
133  $normalizedParams = ‪$request->getAttribute('normalizedParams');
134  if ($normalizedParams instanceof ‪NormalizedParams) {
135  return $normalizedParams->getRequestHost();
136  }
137  return GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST');
138  }
139 
140  protected function ‪resolveRequestDir(ServerRequestInterface ‪$request): string
141  {
142  $normalizedParams = ‪$request->getAttribute('normalizedParams');
143  if ($normalizedParams instanceof ‪NormalizedParams) {
144  return $normalizedParams->getRequestDir();
145  }
146  return GeneralUtility::getIndpEnv('TYPO3_REQUEST_DIR');
147  }
148 }
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\resolveReferrerType
‪resolveReferrerType()
Definition: ReferrerEnforcer.php:112
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer
Definition: ReferrerEnforcer.php:31
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\__construct
‪__construct(ServerRequestInterface $request)
Definition: ReferrerEnforcer.php:48
‪TYPO3\CMS\Core\Http\Security
Definition: InvalidReferrerException.php:16
‪TYPO3\CMS\Core\Http\Security\MissingReferrerException
Definition: MissingReferrerException.php:24
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\$request
‪ServerRequestInterface $request
Definition: ReferrerEnforcer.php:38
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\resolveRequestDir
‪resolveRequestDir(ServerRequestInterface $request)
Definition: ReferrerEnforcer.php:137
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\TYPE_REFERRER_SAME_SITE
‪const TYPE_REFERRER_SAME_SITE
Definition: ReferrerEnforcer.php:33
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\handle
‪handle(array $options=null)
Definition: ReferrerEnforcer.php:55
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\$requestDir
‪string $requestDir
Definition: ReferrerEnforcer.php:46
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\TYPE_REFERRER_EMPTY
‪const TYPE_REFERRER_EMPTY
Definition: ReferrerEnforcer.php:32
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\resolveRequestHost
‪resolveRequestHost(ServerRequestInterface $request)
Definition: ReferrerEnforcer.php:128
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:42
‪TYPO3\CMS\Core\Http\Security\InvalidReferrerException
Definition: InvalidReferrerException.php:24
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\TYPE_REFERRER_SAME_ORIGIN
‪const TYPE_REFERRER_SAME_ORIGIN
Definition: ReferrerEnforcer.php:34
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\$requestHost
‪string $requestHost
Definition: ReferrerEnforcer.php:42
‪TYPO3\CMS\Core\Http\NormalizedParams
Definition: NormalizedParams.php:32
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer\resolveAbsoluteWebPath
‪resolveAbsoluteWebPath(string $target)
Definition: ReferrerEnforcer.php:105
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:25