PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.13.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.13.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Nonce.php
matomo / app / core Last commit date
API 3 years ago Access 3 years ago Application 4 years ago Archive 3 years ago ArchiveProcessor 3 years ago Archiver 5 years ago AssetManager 3 years ago Auth 3 years ago Category 5 years ago Changes 4 years ago CliMulti 4 years ago Columns 3 years ago Concurrency 3 years ago Config 4 years ago Container 4 years ago CronArchive 3 years ago DataAccess 3 years ago DataFiles 5 years ago DataTable 3 years ago Db 3 years ago DeviceDetector 3 years ago Email 5 years ago Exception 4 years ago Http 4 years ago Intl 4 years ago Mail 4 years ago Measurable 5 years ago Menu 3 years ago Metrics 4 years ago Notification 4 years ago Period 4 years ago Plugin 3 years ago ProfessionalServices 4 years ago Report 5 years ago ReportRenderer 3 years ago Scheduler 4 years ago Segment 3 years ago Session 4 years ago Settings 3 years ago Tracker 3 years ago Translation 4 years ago UpdateCheck 5 years ago Updater 3 years ago Updates 3 years ago Validators 4 years ago View 4 years ago ViewDataTable 3 years ago Visualization 4 years ago Widget 5 years ago .htaccess 6 years ago Access.php 4 years ago Archive.php 4 years ago ArchiveProcessor.php 4 years ago AssetManager.php 4 years ago Auth.php 5 years ago AuthResult.php 5 years ago BaseFactory.php 5 years ago Cache.php 5 years ago CacheId.php 5 years ago CliMulti.php 4 years ago Common.php 3 years ago Config.php 3 years ago Console.php 4 years ago Context.php 5 years ago Cookie.php 3 years ago CronArchive.php 3 years ago DataArray.php 4 years ago DataTable.php 3 years ago Date.php 4 years ago Db.php 4 years ago DbHelper.php 4 years ago Development.php 5 years ago ErrorHandler.php 5 years ago EventDispatcher.php 3 years ago ExceptionHandler.php 4 years ago FileIntegrity.php 5 years ago Filechecks.php 4 years ago Filesystem.php 3 years ago FrontController.php 3 years ago Http.php 3 years ago IP.php 4 years ago Log.php 4 years ago LogDeleter.php 4 years ago Mail.php 4 years ago Metrics.php 3 years ago NoAccessException.php 5 years ago Nonce.php 3 years ago Notification.php 5 years ago NumberFormatter.php 4 years ago Option.php 4 years ago Period.php 5 years ago Piwik.php 3 years ago Plugin.php 4 years ago Profiler.php 4 years ago ProxyHeaders.php 5 years ago ProxyHttp.php 3 years ago QuickForm2.php 5 years ago RankingQuery.php 3 years ago ReportRenderer.php 4 years ago Segment.php 4 years ago Sequence.php 5 years ago Session.php 3 years ago SettingsPiwik.php 3 years ago SettingsServer.php 5 years ago Singleton.php 5 years ago Site.php 3 years ago SiteContentDetector.php 3 years ago SupportedBrowser.php 3 years ago TCPDF.php 5 years ago Theme.php 5 years ago Timer.php 5 years ago Tracker.php 4 years ago Twig.php 4 years ago Unzip.php 5 years ago UpdateCheck.php 5 years ago Updater.php 4 years ago UpdaterErrorException.php 5 years ago Updates.php 5 years ago Url.php 4 years ago UrlHelper.php 3 years ago Version.php 3 years ago View.php 3 years ago bootstrap.php 3 years ago dispatch.php 5 years ago testMinimumPhpVersion.php 3 years ago
Nonce.php
242 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9 namespace Piwik;
10
11 use Piwik\Session\SessionNamespace;
12
13 /**
14 * Nonce class.
15 *
16 * A cryptographic nonce -- "number used only once" -- is often recommended as
17 * part of a robust defense against cross-site request forgery (CSRF/XSRF). This
18 * class provides static methods that create and manage nonce values.
19 *
20 * Nonces in Piwik are stored as a session variable and have a configurable expiration.
21 *
22 * Learn more about nonces [here](http://en.wikipedia.org/wiki/Cryptographic_nonce).
23 *
24 * @api
25 */
26 class Nonce
27 {
28 /**
29 * Returns an existing nonce by ID. If none exists, a new nonce will be generated.
30 *
31 * @param string $id Unique id to avoid namespace conflicts, e.g., `'ModuleName.ActionName'`.
32 * @param int $ttl Optional time-to-live in seconds; default is 5 minutes. (ie, in 5 minutes,
33 * the nonce will no longer be valid).
34 * @return string
35 */
36 public static function getNonce($id, $ttl = 600)
37 {
38 // save session-dependent nonce
39 $ns = new SessionNamespace($id);
40 $nonce = $ns->nonce;
41
42 // re-use an unexpired nonce (a small deviation from the "used only once" principle, so long as we do not reset the expiration)
43 // to handle browser pre-fetch or double fetch caused by some browser add-ons/extensions
44 if (empty($nonce)) {
45 // generate a new nonce
46 $nonce = md5(SettingsPiwik::getSalt() . time() . Common::generateUniqId());
47 $ns->nonce = $nonce;
48 }
49
50 // extend lifetime if nonce is requested again to prevent from early timeout if nonce is requested again
51 // a few seconds before timeout
52 $ns->setExpirationSeconds($ttl, 'nonce');
53
54 return $nonce;
55 }
56
57 /**
58 * Returns if a nonce is valid and comes from a valid request.
59 *
60 * A nonce is valid if it matches the current nonce and if the current nonce
61 * has not expired.
62 *
63 * The request is valid if the referrer is a local URL (see {@link Url::isLocalUrl()})
64 * and if the HTTP origin is valid (see {@link getAcceptableOrigins()}).
65 *
66 * @param string $id The nonce's unique ID. See {@link getNonce()}.
67 * @param string $cnonce Nonce sent from client.
68 * @param null|string $expectedReferrerHost The expected referrer host for the HTTP referrer URL.
69 * @return bool `true` if valid; `false` otherwise.
70 */
71 public static function verifyNonce($id, $cnonce, $expectedReferrerHost = null)
72 {
73 // load error with message function.
74 $error = self::verifyNonceWithErrorMessage($id, $cnonce, $expectedReferrerHost);
75 return $error === "";
76 }
77
78 /**
79 * Returns error message
80 *
81 * A nonce is valid if it matches the current nonce and if the current nonce
82 * has not expired.
83 *
84 * The request is valid if the referrer is a local URL (see {@link Url::isLocalUrl()})
85 * and if the HTTP origin is valid (see {@link getAcceptableOrigins()}).
86 *
87 * @param string $id The nonce's unique ID. See {@link getNonce()}.
88 * @param string $cnonce Nonce sent from client.
89 * @param null $expectedReferrerHost The expected referrer host for the HTTP referrer URL.
90 * @return string if empty is valid otherwise return error message
91 */
92 public static function verifyNonceWithErrorMessage($id, $cnonce, $expectedReferrerHost = null)
93 {
94 $ns = new SessionNamespace($id);
95 $nonce = $ns->nonce;
96
97 $additionalErrors = '';
98
99 // The Session cookie is set to a secure cookie, when SSL is mis-configured, it can cause the PHP session cookie ID to change on each page view.
100 // Indicate to user how to solve this particular use case by forcing secure connections.
101 if (Url::isSecureConnectionAssumedByPiwikButNotForcedYet()) {
102 $additionalErrors = '<br/><br/>' . Piwik::translate('Login_InvalidNonceSSLMisconfigured',
103 array(
104 '<a target="_blank" rel="noreferrer noopener" href="https://matomo.org/faq/how-to/faq_91/">',
105 '</a>',
106 'config/config.ini.php',
107 '<pre>force_ssl=1</pre>',
108 '<pre>[General]</pre>',
109 )
110 );
111 }
112
113 // validate token
114 if (empty($cnonce) || $cnonce !== $nonce) {
115 return Piwik::translate('Login_InvalidNonceToken');
116 }
117
118 // validate referrer
119 $referrer = Url::getReferrer();
120 if (empty($expectedReferrerHost) && !empty($referrer) && !Url::isLocalUrl($referrer)) {
121 return Piwik::translate('Login_InvalidNonceReferrer', array(
122 '<a target="_blank" rel="noreferrer noopener" href="https://matomo.org/faq/how-to-install/faq_98">',
123 '</a>'
124 )) . $additionalErrors;
125 }
126
127 //referrer is different expected host
128 if (!empty($expectedReferrerHost) && !self::isReferrerHostValid($referrer, $expectedReferrerHost)) {
129 return Piwik::translate('Login_InvalidNonceUnexpectedReferrer') . $additionalErrors;
130 }
131
132 // validate origin
133 $origin = self::getOrigin();
134 if (!empty($origin) &&
135 ($origin == 'null'
136 || !in_array($origin, self::getAcceptableOrigins()))
137 ) {
138 return Piwik::translate('Login_InvalidNonceOrigin') . $additionalErrors;
139 }
140
141 return '';
142 }
143
144 // public for tests
145 public static function isReferrerHostValid($referrer, $expectedReferrerHost)
146 {
147 if (empty($referrer)) {
148 return false;
149 }
150
151 $referrerHost = Url::getHostFromUrl($referrer);
152 return preg_match('/(^|\.)' . preg_quote($expectedReferrerHost) . '$/i', $referrerHost);
153 }
154
155 /**
156 * Force expiration of the current nonce.
157 *
158 * @param string $id The unique nonce ID.
159 */
160 public static function discardNonce($id)
161 {
162 $ns = new SessionNamespace($id);
163 $ns->unsetAll();
164 }
165
166 /**
167 * Returns the **Origin** HTTP header or `false` if not found.
168 *
169 * @return string|bool
170 */
171 public static function getOrigin()
172 {
173 if (!empty($_SERVER['HTTP_ORIGIN'])) {
174 return $_SERVER['HTTP_ORIGIN'];
175 }
176 return false;
177 }
178
179 /**
180 * Returns a list acceptable values for the HTTP **Origin** header.
181 *
182 * @return array
183 */
184 public static function getAcceptableOrigins()
185 {
186 $host = Url::getCurrentHost(null);
187
188 if (empty($host)) {
189 return array();
190 }
191
192 // parse host:port
193 if (preg_match('/^([^:]+):([0-9]+)$/D', $host, $matches)) {
194 $host = $matches[1];
195 $port = $matches[2];
196 $origins = array(
197 'http://' . $host,
198 'https://' . $host,
199 );
200 if ($port != 443) {
201 $origins[] = 'http://' . $host .':' . $port;
202 }
203 $origins[] = 'https://' . $host . ':' . $port;
204 } elseif (Config::getInstance()->General['force_ssl']) {
205 $origins = array(
206 'https://' . $host,
207 'https://' . $host . ':443',
208 );
209 } else {
210 $origins = array(
211 'http://' . $host,
212 'https://' . $host,
213 'http://' . $host . ':80',
214 'https://' . $host . ':443',
215 );
216 }
217
218 return $origins;
219 }
220
221 /**
222 * Verifies and discards a nonce.
223 *
224 * @param string $nonceName The nonce's unique ID. See {@link getNonce()}.
225 * @param string|null $nonce The nonce from the client. If `null`, the value from the
226 * **nonce** query parameter is used.
227 * @throws \Exception if the nonce is invalid. See {@link verifyNonce()}.
228 */
229 public static function checkNonce($nonceName, $nonce = null, $expectedReferrerHost = null)
230 {
231 if ($nonce === null) {
232 $nonce = Common::getRequestVar('nonce', null, 'string');
233 }
234
235 if (!self::verifyNonce($nonceName, $nonce, $expectedReferrerHost)) {
236 throw new \Exception(Piwik::translate('General_ExceptionNonceMismatch'));
237 }
238
239 self::discardNonce($nonceName);
240 }
241 }
242