upvote
This is fundamentally a CSRF issue and framing CSRF as an access control issue often yields to wrong conclusions. With CSRF you might face the situation that the request has a valid session cookie, but is actually created by an attacker coercing the victim's browser into sending a request unbeknownst to the victim.

This case gets more and more complicated with browser defenses such as SameSite cookies or fetch headers you can use to mitigate this case, but let's ignore that for now.

To drive my point home, similar to how ensuring the content-type is set correctly on your JSON endpoint prevents CSRF, it's actually also a very real defense to require a custom header to be set, e.g.

  I-Promise-To-Not-Be-Malicious: true
Requiring this header will prevent CSRF because browsers won't allow you to set that cross-origin (unless of course you allow anyone to set it via CORS)
reply
Regarding the first part, it's easier than you might think to have a false sense of security.

I've seen a web application that did, in fact, check the Content-Type header to make sure that "application/json" was there - but it didn't check that the header value started with that. That meant that setting the header to "multipart/form-data; boundary=application/json" was enough to bypass a CORS preflight!

reply
deleted
reply