matomo
matomo copied to clipboard
`POST` to `matomo.php` Endpoint Returns 204 When Setting An `Origin` Header Not On The `cors_domains`
According to the documentation in the Matomo FAQ, CORS settings can be set by setting the cors_domains
array in the config.ini.php
to only allow certain domains to interact. However even if this is set, when sending a POST
request to the matomo.php
endpoint with a domain in the Origin
request header that is not on the list still returns a 204
instead of an error.
Expected Behavior
When the Origin
request header is set to a URL not on the list, the response should be some sort of 4xx
response.
Current Behavior
Response is a 204
Possible Solution
Set behavior to return a 401
in this instance
Steps to Reproduce (for Bugs)
- Set a value in
cors_domains
in theconfig.ini.php
to your domain. - Verify these values on the
System
->General Settings
page under theCross-Origin Resource Sharing (CORS) domains
section. - Send a
POST
request to the/matomo.php
endpoint with theOrigin
header set to a value not in thecors_domains
array (for example,https://evil.site
- Observe response is
204
.
Context
This bug could allow malicious actors to hit endpoints from environments outside the allowed websites.
Your Environment
- Matomo Version:
4.9.0
- PHP Version:
8.0.17
- Server Operating System: Linux (using Matomo docker container
4.0.9-apache
) - Additionally installed plugins: None
- Browser: Observed in Chrome
100.0.4896.127
and using Postman - Operating System: Mac OS X
@Zozman thanks for the bug report, I think that's a bug I made in this PR, https://github.com/matomo-org/matomo/pull/19030.
Here should be instead of *
, I believe should be a combination of cors_domains
and sites domains in the database. ping @sgiehl
https://github.com/matomo-org/matomo/blob/dc753b2fc6e691d0830ec03143ae06c091474296/core/Tracker.php#L119
should we assign this issue to the 5.0 milestone, since it's breaking changes?
I'm not sure. Thinking of tracking I'm wondering if 204 is maybe actually the correct response since the tracking request was processed and we would want to avoid that because of https://github.com/matomo-org/matomo/blob/4.10.1/js/piwik.js#L2843-L2850 we would retry that tracking request.
A 204 would describe exactly above. Request was executed but no response/content.
AFAIK when sending a tracking request and there is a CORS error then the request itself was still executed. It's only that the response wasn't readable for the client. So we'd want to make sure to not send every tracking request twice.
I guess that depends on the expectation. I would actually also assume that a configured cors domain would also disallow requests coming from other origins. In that case it would be correct to send a 403 Forbidden
. We then would need to handle the 403 in another way in tracking js for sure.
You can see this in the examples on https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS as well that these send HTTP 2XX (200 and 204) headers. And the browsers decided if the client can read the response.
Also
CORS failures result in errors but for security reasons, specifics about the error are not available to JavaScript. All the code knows is that an error occurred. The only way to determine what specifically went wrong is to look at the browser's console for details.
![image](https://user-images.githubusercontent.com/273120/172851607-8eae8eb5-5885-477f-a3df-64dad4b53991.png)
The browser console already shows correctly when a CORS error happens
@Zozman What exactly was you intention when creating the issue? Do you want to be able to block tracking requests that are not coming from the "correct" origin? In that case I guess this issue is actually the same as #20871 I'm asking because the CORS headers are actually only meant to disallow the browser from using content from other domains. But those headers itself wouldn't let any request fail. So the request would still be sent, but the response is discarded.
@sgiehl Essentially our view is if an Origin not on the Cross-Origin Resource Sharing (CORS) domains
list when one is set hits the endpoint, it should return a 401
or some other sort of error because that Origin shouldn't be allowed. It shouldn't return a "successful" response like a 204
.
@Zozman Ok, so it's around "blocking" requests. Personally I would avoid reusing the CORS config for this. As there could be good reasons for having another set of domains in the CORS config and in the list of domains you want to allow as tracking origin. Also how would you handle requests without an origin? Should those be discarded in any case then?
Note: In terms of security this won't have much benefit. If someone wants to send requests to you endpoint with random data, they can do it nevertheless by sending an origin header.
@sgiehl I'm just confused about the fact that there's an explicit list of domains that should be allowed to send data to a Matomo instance and then treating requests from not those domains as OK. Without this, someone could setup malicious JavaScript on any website on the internet to hit a site's Matomo endpoint all day and get back successful responses. I understand anyone can hit it, but 20x
means it's fine to do when it shouldn't be, right?
I'm not very deep into the CORS specification. But either we should fully block a request if the origin doesn't match and return a 40x status. Or we allow tracking from any source and return a 204, like it currently is. Processing the request, but returning a 40x if the origin doesn't match might be even more confusing.
And yes, in theory any website could start tracking to a random instance. But the website configuration allows to discard all requests that don't match the configured domains. So you can at least prevent tracking random urls.
Anyway. I would suggest to introduce a new config that allows to enable blocking requests from origins that are not on the CORS list. That way anyone who wants to use that could enable it easily.