Allowing CORS in PHP, the right way

Hii Guys,

It's a very common thing to see during web development, the dreaded CORS error.

I also see that a lot of answers to this issue say to add this to the PHP script:

header('Access-Control-Allow-Origin: *');          

This code, however, just makes my skin crawl because what it effectively does is bypass CORS, which is a security hazard.
As such, in this post, we'll be looking into how to properly fix this issue, without compromising security.
Please note that there is a very VERY specific case where using the * may actually be desirable and this is with public APIs.
But in this case, you should still be careful about what you do and do not allow to be done through said public API.

What is CORS?


CORS or "Cross-Origin Resource Sharing" is a mechanism that used a set of additional HTTP headers, to inform a web application whether it has permission to access requested resources from a server on a different domain ("origin").
It informs the client that a certain domain may or may not be trusted to access a certain resource.
Say, domain https://evilsite.evil trying to make a request to https://legitsite.legit to, for example, loot someone's bank account.
$.ajax({
  url: 'https://legitsite.legit/api/v1/transfer-money',
  method: 'POST',
  data: { from: '1234', to: '5678', amount: 50 }
});          


Implying you have no further protections (like CSRF Tokens, requiring a user to enter his/her security code, a captcha etc.) this will just wire over 50 bucks (why just 50? most people have 50 bucks on their account so it’s less likely to be blocked due to insufficient funds… also 50 bucks will raise less suspicion) to my account just like that.

By using CORS (and in particular, only allowing domains you strictly own), the client will just step in before the actual request (it happens in 2 stages: pre-flight and flight, CORS check happens during pre-flight, actual data transfer in flight) and say: “hold the fuck up cowboy, we’re not gonna continue this request” and the user won’t lose 50 bucks (sad me, head over to the donation page to fork me over 50 bucks yourself?).

Then how should I do it?


The solution to this issue is quite simple, only allow domains that you have explicit control over or trust.
This example is written in pure PHP, so if you use a framework, see it's respective documentation to see if it has this functionality built-in.
// Add our allowed domains
$allowedDomains = ['https://legitsite.legit', 'https://partnersite.legit', 'https://otherpartner.legit'];

// Check if our origin is in the allowed list
if(!in_array($_SERVER['HTTP_ORIGIN'], $allowedDomains)) {
  // ... Handle unauthorized domain
}

// Set our CORS header, allowing this domain
header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);

// ... Continue with action          


And honestly, that's it really.
Very simple, yet effective without compromising on security.

I hope you guys liked this post, if you did, feel free to share it around so people will stop using that hideous *for this.
That's it for now.

Dismissed.

Comments


Leave a comment


Please login to leave comment!