Crashtest Security Blog

Multiple Values Access-Control-Allow-Origin

Nov 6, 2017 8:26:00 AM / by Janosch Maier

Secure Third Party Access to a REST API

 

Stay in control of who can access your services.

 

Enforcing security policies on web applications these days is 'relatively easy' by using the correct headers in HTTP responses. Take the following example of an application:

  • https://example.org delivers the frontend of the great example applications to its users. This is the domain a user knows.
  • https://api.example.org is handling all information. If the user logs in, then the frontend sends a request to this domain and changes according to the response.

 

In this case it should not be possible for anybody else but the frontend to access the API. By now browsers try to protect the user and try to block malicious requests. Such a request would be if a user is visiting https://malicious.example.org and the web application there would try to access https://api.example.org. To prevent that, the webserver delivering the API can send the Access-Control-Allow-Origin header as follows:


Access-Control-Allow-Origin: https://example.org

 

This way the malicious website has no more access to our API if the user is using a recent browser.

 
No security headers set? Better use them when developing a web application.

 

If the application setup becomes more complex, things get much more complicated to configure. Assume that there are more systems:

 

There is no possibility for the Access-Control-Allow-Origin header to contain multiple domains, like separating different domains via spaces or comma. Besides specifying a single domain, only '*' is another valid option, which would allow access from everywhere. And this is no secure option in this case.

 

Therefore the API needs to check the origin of the request and adjust the header field accordingly. It can use the 'Origin' header on the request to check who is trying to access the resource. If it is one of the allowed domains, it sets the Access-Control-Allow-Origin accordingly. Otherwise it just sets it to https://example.org so that the request is blocked by the browser. The following example explains how a Laravel project can make use of a middleware to set this header correctly:

<?php

class
CORSMiddleware
{
[...]
   /**
* Add Access Control headers.
*
*
@param \Illuminate\Http\Request $request
*
@param \Illuminate\Http\Response $response
*
*
@return \Illuminate\Http\Response
*/
protected function addAccessControlHeaders($request, $response)
{
$possibleOrigins = [
'https://example.com',
'https://api.example.com',
'https://staging.example.com',
'https://payment.example.org',
];

if (env('APP_ENV') == 'development') {
$possibleOrigins[] = 'https://localhost:8080';
}

if (in_array($request->header('origin'), $possibleOrigins)) {
$origin = $request->header('origin');
} else {
$origin = 'https://example.com';
}

$headers = [
'Access-Control-Allow-Origin' => $origin,
'Vary' => 'Origin',
];

foreach ($headers as $header => $value) {
$response->header($header, $value);
}

return $response;
}
}

 

In addition to the Access-Control-Allow-Origin header, the Vary header is set so that the browser knows that the response of this API may vary depending on the origin. Therefore it will not use any cached response when the API is called from a different frontend site in the same browser.

 

Sources:

Topics: VulnerabilityAssessment

Janosch Maier

Written by Janosch Maier

Co-Founder @ Crashtest Security. I write and give workshops regarding Web Security