Firefox cors error

How to fix Cross Origin Request Security (CORS) error in Firefox, Chrome and IE......

Now a days all the latest browsers are developed to support Cross Origin Request Security (CORS), however sometimes CORS still creates problem and it happens due to Java script or Ajax requested from another domain. This can be resolved if appropriate certificate is installed in your browser.

There are many ways that you can resolved this error at browser level. Follow the steps to fix Cross Origin Request Security by enabling CORS in different browsers-

Fix Cross Origin Request Security (CORS) error Firefox

There are two ways to fix CORS error in Firefox. If method-1 does not work for you please follow method-2. To follow method-2 you required firebug to be installed in the browser.

Method-1

1) Open Firefox browser and in the address bar type about:config and hit Enter button.

cors1

2) Click on I’ll be careful, I promise! Button.

cors2

3) In search box type origin.

cors3

4) Look for security.fileuri.strict_origin_policy option.

cors4

5) Double click on security.fileuri.strict_origin_policy will change the status from true to false.

That’s all. Restart Firefox browser and reload the URL . Navigate the page which was showing Cross Origin Request Security (CORS) error. This time CORS error should not be happen.

If you still experiencing Cross Origin Request Security (CORS) error please follow the next method-

Method-2

  • Open Firefox browser and load the page.
  • Perform the operation which is throwing Cross Origin Request Security (CORS) error.
  • Open firebug and copy the URL which is throwing Cross Origin Request Security (CORS) error.
  • Load the same URL in another tab in same Firefox browser.
  • Once you open the URL in another tab will ask you to add the certificate.

After adding the certificate will resolve Cross Origin Request Security (CORS) error and now you will not be getting this error.

Fix Cross Origin Request Security (CORS) error in Chrome

1) Click on Start icon and type chrome in search box.

cors5

2) Right click on Google Chrome and select Properties.

cors6

3) On properties window, under Target box add –disable-web-security at the end and then click on Apply button.

cors7

While clicking on Apply button could ask you to provide system password. If asks please add your system password and then click on OK button.

Here you have successfully disabled web security. Now Cross Origin Request Security (CORS) Error should not come.

Fix Cross Origin Request Security (CORS) error in IE

1) Open IE and click on Tools and then click on Internet Options.

cors8

2) On Internet Options window click on Security tab and then click on Custom level button.

cors9

3) On Security Settings window look for Access data sources across domain and then Click on Enable radio button.

cors10

4) Click OK and then Click OK again to save the changes.

You are done here. Now Cross Origin Request Security (CORS) has been disabled now. You should not face the same issue again.

I’m using aws-amplify to query API Gateway (configured through serverless) to trigger a lambda.

I have no trouble accessing some resources except for one, which I get using query string parameters. This is the only difference with the other queries. Yet, I get CORS error and cannot see any log for the lambda that should have been triggered nor can I see the query in the browser network console.

What confuses me is that I get this error only in firefox and not in chrome.

In my serverless configuration file for the endpoint, I do have cors to true:

  myEndpoint:
    handler: myEndpoint.main
    events:
      - http:
          path: myEndpoint
          method: get
          cors: true
          authorizer: aws_iam
          request:
            parameters:
              querystrings:
                x: true
                y: true
                z: true

I configured the custom authorizer

Resources:
  GatewayResponseDefault4XX:
    Type: 'AWS::ApiGateway::GatewayResponse'
    Properties:
      ResponseParameters:
         gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
         gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
      ResponseType: DEFAULT_4XX
      RestApiId:
        Ref: 'ApiGatewayRestApi'
  GatewayResponseDefault5XX:
    Type: 'AWS::ApiGateway::GatewayResponse'
    Properties:
      ResponseParameters:
         gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
         gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
      ResponseType: DEFAULT_5XX
      RestApiId:
        Ref: 'ApiGatewayRestApi'

In my lambda, I’m adding CORS headers before response

    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Credentials": true
    }

All of this is working well except for that one request with query string parameters, for which there’s a CORS error logged in the console, but not log in network and no log in CloudWatch.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://...?x=1&y=2&z=3. (Reason: CORS request did not succeed).[Learn More]

What makes it even harder for me to understand is that when I remove my parameters, I get a 502 error from the lambda (as should be) and can read what’s wrong in CloudWatch logs

    let params = {
      queryStringParameters: {
        x: 1,
        y: 2,
        z: 3
      }
    };
    API.get("api", '/myEndpoint', params); // this causes CORS error
    API.get("api", '/myEndpoint', {}); // this causes 502 (as it should)

Another thing that puzzles me is that this worked for a while and then stopped without me changing anything (except uploading a front-end to S3 and CloudFront but I fail to see where that could do something). I thought this might be caching issue but when I go to API Gateway > Stages > myStage, «Enable API cache» is not checked.

I’m really confused and would appreciate any help. Thank you.

What is CORS?

CORS is an acronym. It stands for ‘Cross-Origin Resource Sharing’.

If you are involved in creating, configuring or maintaining a website then you may need to know about CORS.

Web browsers have a security feature known as the same-origin policy. This policy prevents code on one website from
talking to a different website unless certain conditions are met.

Roughly speaking you can think of ‘origin’ as meaning ‘website’ or ‘server’. So when we talk about ‘same-origin’ we mean
‘same-website’ or ‘same-server’. To find out more about exactly how origin is defined see
What does ‘origin’ mean?.

In short, CORS is a way to turn off this security feature to allow AJAX requests to a different site.

The site making the AJAX request can’t just turn off security. That would be back-to-front. As far as the browser is
concerned that site might be malicious and can’t be trusted. It is the server receiving the AJAX request that decides
whether to allow CORS.

Why am I getting a CORS error when I’m not even using CORS?

If your website has attempted to make an HTTP request to a different site then the browser will try to use CORS. You
don’t have a choice, it happens automatically. If the target server doesn’t have CORS enabled then the request will fail
and the browser will log a CORS error to the console.

Using the same domain with two different port numbers is not sufficient to avoid CORS. The port number is considered
to be part of the origin when the browser decides whether or not to use CORS.

What does ‘origin’ mean?

Consider the following URL:

http://www.example.com:3456/path?query=text

The origin for this URL would be http://www.example.com:3456. It includes the scheme, hostname and port.

http://www.example.com:3456
<scheme> :// <hostname> [ : <port> ]

The port may be omitted if it is the default port for the scheme, so 80 for http or 443 for https.

When the browser makes a CORS request it will include the origin for the current page in the Origin request header.

In JavaScript you can access the current page’s origin using location.origin.

How does CORS work?

Let’s start with the basics.

There are two questions that the browser needs to answer:

  1. Are you allowed to make the request at all?
  2. Are you allowed to access the response?

There are some requests that are considered simple enough and safe enough that the first stage is skipped. We’ll come
back to that later.

For the second question, the browser assumes by default that you can’t access the response for a cross-origin request.
That includes the response body, the response headers and the status code.

In addition to the usual request headers the browser will also include an Origin header, containing the origin of the
page making the request. Note this is added automatically by the browser, you can’t add it yourself.

The server then needs to grant permission for the response to be exposed to the client-side code. It does this by
including the response header Access-Control-Allow-Origin. The value of this header must be identical to the value of
the Origin header it received. It can also use the special value * to allow any origin. Any other value will cause
the CORS check to fail in the browser.

It is really important to understand that Access-Control-Allow-Origin is a response header sent by the server. It is
NOT a request header. It is a very common mistake to try to set this header on the request, which won’t help at
all.

// Don't copy this code, it is wrong!!!
axios.get(url, {
  headers: {
    // This is in the wrong place. It needs to be on the server.
    'Access-Control-Allow-Origin': '*'
  }
})

In addition, only a limited subset of the response headers will be exposed by default. See
Why can’t I access the response headers in my JavaScript code? for more information.

If a request is not deemed ‘simple’ and ‘safe’ then it must first undergo a preflight check to determine whether to
allow the request at all. See What is a preflight request? for more information.

Why am I seeing an OPTIONS request instead of the GET/POST/etc. request I wanted?

What is a preflight request?

The term is a reference to the preflight checks carried out by pilots.

It is a request generated automatically by the web browser. It is used to check whether the server is willing to allow
the original request.

Before CORS existed you couldn’t make AJAX requests to other servers. However, you could make requests by other means,
such as by submitting a form or including a <script src="..."> in your page.

Those alternative means of making requests had some limitations. e.g.:

  • You could only make GET and POST requests.
  • There was no way to set custom request headers.
  • A POST request could only have a content-type of application/x-www-form-urlencoded, multipart/form-data or
    text/plain.

When CORS was introduced it was important to ensure that no new security holes were opened up. If an AJAX request
tried to do something beyond the limitations listed above then it might expose a new security vulnerability in the
target server.

To get around this problem the browser first checks with the target server to see whether it will allow the main
request. This check takes the form of an HTTP OPTIONS request. Here OPTIONS refers to the request method, it’s one
of the alternatives to GET and POST. The request headers of the OPTIONS request describe the main request to the
server and then the server responds via the response headers.

An OPTIONS request was chosen for this purpose because most web servers already implemented some form of OPTIONS
request handling and such requests should always be harmless to the server.

You don’t have direct control over the preflight request, it’s made automatically by the browser. It will look something
like this:

OPTIONS /api-path HTTP/1.1
Origin: http://localhost:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type

Other headers will be included but they aren’t important here. Breaking this down line-by-line:

  1. The path /api-path shown here is just an example and will match the URL path of the original request.
  2. The Origin header will match the origin of the page making the request. See What does ‘origin’ mean?.
    This is exactly the same as the Origin header that will be included on the main request.
  3. The header Access-Control-Request-Method indicates the request method of the main request.
  4. The header Access-Control-Request-Headers is a comma-separated list of custom headers that were set on the request.
    Headers set by the browser aren’t included, so any headers listed here were set somewhere in the code that attempted
    the original request. It doesn’t tell us the values of those headers, just that they were set to something other than
    their default values.

To allow this request, the server response should look like this:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: content-type

Again, breaking this down line-by-line:

  1. The status code must be in the range 200299 for a preflight request to succeed.
  2. Just like for the main request, Access-Control-Allow-Origin must either match the Origin or be *.
  3. The response header Access-Control-Allow-Methods is a comma-separated list of allowed request methods. GET,
    POST and HEAD requests are always allowed, even if they aren’t included in the list.
  4. Access-Control-Allow-Headers is also a comma-separated list. For the request to be allowed it must include all of
    the headers that were listed in Access-Control-Request-Headers.

If any of the CORS response headers are dynamically generated based on the request headers then those request headers
should be listed in the Vary response header. e.g. Vary: Origin. This helps to avoid caching problems.

No request body will be sent for a preflight request and the response body will be ignored.

My request works fine in Postman/cURL/etc.. Why do I get a CORS error in the browser?

The same-origin policy is a security feature built into web browsers. It doesn’t apply if you make requests using
tools such as Postman or cURL. Concepts such as ‘same-origin’ and ‘cross-origin’ don’t even make sense in that context.
Same origin as what? There is no current page making the request, so there is no origin to compare.

Any CORS errors you see in the browser console are not generated by the server. At the network level the request
probably succeeded. The browser may well have received exactly the same response that you see with Postman or cURL. It’s
the browser that performs the CORS checks and blocks access to the response in JavaScript if those checks fail.

The biggest difference between a browser and tools like Postman is the preflight OPTIONS request. As those tools don’t
use CORS they aren’t going to send a preflight request automatically. However, a preflight is just an HTTP request so it
is possible to send it manually instead:

  • How can I use cURL to test a preflight request?
  • Can Postman send a preflight request?

Within the browser it’s usually pretty clear from the error message whether it’s the preflight request that’s failing.

How can I use cURL to test a preflight request?

In Chrome or Firefox you should be able to see the preflight OPTIONS request in the Network tab of the developer
tools. Right-clicking on the request should present an option to Copy as cURL.

To make the copied request useful you will also need to add the -I option. This includes the response headers in the
output.

Most of the request headers included by a browser aren’t necessary from a CORS perspective. Servers will usually ignore
those other headers when responding to a preflight request. Generally a much simpler cURL request will suffice:

curl 
  -I 
  -X OPTIONS 
  -H "Origin: http://localhost:8080" 
  -H "Access-Control-Request-Method: POST" 
  -H "Access-Control-Request-Headers: Content-Type" 
  http://localhost:3000/api

Breaking this down:

  1. The symbols are used to break the command over multiple lines. You can remove them and put the whole thing on one
    line if you prefer.
  2. As mentioned previously the -I will output the response headers.
  3. The -X is used to set the request method. For a preflight this must be OPTIONS.
  4. -H adds a request header.
  5. The values of the three headers will need changing to match the request you are trying to make. You should omit
    Access-Control-Request-Headers if there are no custom headers.
  6. The final line is the URL of the target server. Again this is something you will need to change to match the request
    you are trying to make.

Can Postman send a preflight request?

A preflight request is just an HTTP request, so it can be sent using Postman.

To send the request manually you’ll need to select OPTIONS for the request method and then set suitable values for the
headers Origin, Access-Control-Request-Method and Access-Control-Request-Headers.

If you want a preflight request to be generated automatically then you could use Postman’s Pre-request Script feature
instead. The code below is an example of how to generate a preflight request for another request. You should be able to
drop this code straight into the Pre-request Script tab for your target request:

(function () {
  const request = pm.request
  const url = request.url.toString()
  const requestMethod = request.method
  const headers = request.headers.toObject()
  const origin = headers.origin

  if (!origin) {
    console.log(`The request must have an Origin header to attempt a preflight`)
    return
  }

  delete headers.origin

  const requestHeaders = Object.keys(headers).join(', ')

  if (!['GET', 'HEAD', 'POST'].includes(requestMethod)) {
    console.log(`The request uses ${requestMethod}, so a preflight will be required`)
  } else if (requestHeaders) {
    console.log(`The request has custom headers, so a preflight will be required: ${requestHeaders}`)
  } else {
    console.log(`A preflight may not be required for this request but we'll attempt it anyway`)
  }

  const preflightHeaders = {
    Origin: origin,
    'Access-Control-Request-Method': requestMethod
  }

  if (requestHeaders) {
    preflightHeaders['Access-Control-Request-Headers'] = requestHeaders
  }

  pm.sendRequest({
    url,
    method: 'OPTIONS',
    header: preflightHeaders
  }, (err, response) => {
    if (err) {
      console.log('Error:', err)
      return
    }

    console.log(`Preflight response has status code ${response.code}`)
    console.log(`Relevant preflight response headers:`)

    const corsHeaders = [
      'access-control-allow-origin',
      'access-control-allow-methods',
      'access-control-allow-headers',
      'access-control-allow-credentials',
      'access-control-max-age'
    ]

    response.headers.each(header => {
      if (corsHeaders.includes(header.key.toLowerCase())) {
        console.log(`- ${header}`)
      }
    })
  })
})()

This code requires the original request to have an Origin header set. You can see the results of the preflight in the
Postman Console. The code makes no attempt to perform a CORS check on the response headers, you’ll need to verify the
response yourself.

Why am I seeing a preflight OPTIONS request when I’m not setting any custom headers?

The first step to debugging an unexpected preflight request is to check the request headers on the preflight request.
The headers Access-Control-Request-Method and Access-Control-Request-Headers should clarify why the browser thinks a
preflight in required.

First check Access-Control-Request-Method. If it’s set to GET, HEAD or POST then that isn’t the problem. Those 3
request methods are considered safe and won’t trigger a preflight request. For any other values, e.g. PUT or DELETE,
that’s enough to trigger a preflight request.

The other header to check is Access-Control-Request-Headers. This will provide a comma-separated list of header names.
These are the names of the request headers that triggered the preflight request. It won’t tell you the values, just
names. If the preflight succeeds then you’ll be able to find the values on the main request.

Often once you see the names of the headers it’s obvious where they are coming from. But not always. A quick search
through your code can help but sometimes even that doesn’t reveal the source of the rogue headers.

If you’re using a library it may be automatically setting headers for you. Some common examples includes:

  • X-Requested-With being set to XMLHttpRequest.
  • Content-Type. The values application/x-www-form-urlencoded, multipart/form-data and text/plain won’t trigger a
    preflight request but any other value will. Most AJAX libraries will attempt to set the Content-Type header for
    requests that have a body, such as POST requests. Some libraries will automatically set the Content-Type to
    application/json when the body contains JSON data. For a cross-origin request that will trigger a preflight.
  • Authorization. If you’re providing options such as username and password then it is likely that the library will
    be converting them to an Authorization header.

If you still can’t find where the custom header is coming from then you may need to step through the code. Put a
breakpoint just before your request and step into the library code to see exactly what is going on.

How can I avoid the preflight OPTIONS request?

Caching

If you want to cut down the number of preflight requests you should consider using caching. Preflight caching is
controlled using the response header Access-Control-Max-Age.

Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 3600
Vary: Origin

The Vary header is used to identify which request headers were used to generate the response. The cached response
should only be used if the values of those headers are unchanged.

Most browsers will limit the caching time for preflight requests to a few hours, depending on the browser.

The requests must share the same URL to get any benefit from caching. If your URLs are all slightly different, possibly
because they include resource ids, then you may want to consider moving those differences into the request body instead.

Completely avoiding a preflight

Avoiding preflight requests is primarily a server-side problem and may require significant architectural changes
depending on how your application is structured. Ultimately the server dictates the form of the requests and if those
requests require a preflight then there’s nothing the client-side code can do to avoid it.

First you’ll need to limit requests to GET, HEAD or POST. If you’re using other request methods such as PUT or
DELETE then you’ll need to change them to POST.

Some custom request headers are allowed without triggering a preflight, though generally they’re not the most useful
headers. If you have an existing request that is triggering a preflight then the simplest way to confirm which headers
are to blame is to check the value of Access-Control-Request-Headers. See Why am I seeing a preflight OPTIONS request when I’m not setting any custom headers? for
more information.

Most custom headers can either be removed or moved into the request body instead.

To avoid a preflight request the Content-Type header must be one of application/x-www-form-urlencoded,
multipart/form-data or text/plain. If the body of your POST requests is not in one of these three formats then
you’ll need to lie in order to avoid a preflight. If you’re using a third-party library to parse the content then it may
need reconfiguring to cope with the misleading Content-Type header. This can be difficult if your server supports
multiple types of content. You could use different paths for different formats, or use a URL query parameter to pass the
true Content-Type. Either way you may find yourself needing to be inventive to get the parser to understand which
requests it should parse.

The Authorization header can also be problematic as it is commonly used by third-party libraries. Whether this is a
solvable problem will depend on the library you’re using.

Why am I seeing ‘405 — Method Not Allowed’?

There are a few reasons why you might be seeing this error.

A 405 status code usually indicates that a request is using the wrong request method. e.g. Using POST when it should
be GET. That applies to any request, not just CORS requests. Before you do anything else it is worth quickly checking
which request method the server is expecting and making sure that you’ve used the correct one when making the request.
Check the URL too, make sure you haven’t copied it from somewhere else without updating it.

From a CORS perspective the most likely cause of problems is the preflight OPTIONS request. That’s usually pretty easy
to identify as you’ll see an error message in the browser console telling you that the preflight request has failed.
Typically the problem is simply that the server hasn’t been configured to support a preflight OPTIONS request. That
may be a server bug, or it may be that you’re triggering an unnecessary preflight. See
What is a preflight request?. If you have control over the server then also consult the documentation for your
server-side stack to check what is required to enable a CORS preflight request.

Next, use the Network tab of the developer tools in your browser to check exactly which request is failing. Pay
particularly close attention to the request method, don’t just assume it’s what you wrote in your code. Most browsers
allow the columns shown in the Network tab to be configured, so add Method if it isn’t already showing.

If you have the option of checking the server logs then that may also help to provide important clues.

HTTP redirects are also a common source of 405 errors, though not specifically related to CORS. This includes
redirecting from http to https or redirects to add or remove trailing slashes. Depending on how this is implemented
it can cause the request to change method to GET, causing a 405.

What is withCredentials? How do I enable it?

withCredentials is a flag that can be set on XMLHttpRequest for cross-origin requests. It is usually used to enable
cookies. It is also required to enable browser-based HTTP authentication, though that can also be implemented manually.

Note that withCredentials is only required for specific forms of ‘credentials’. Just because you’re using some form of
authentication with credentials doesn’t necessarily mean that you need to enable withCredentials.

If you’re using XMLHttpRequest directly it would be set as follows:

const httpRequest = new XMLHttpRequest();
httpRequest.withCredentials = true;

It can be set at any point prior to calling httpRequest.send().

For making requests with fetch the equivalent of withCredentials is setting credentials to 'include':

fetch(url, {
  credentials: 'include'
});

With jQuery the withCredentials flag can be set using:

jQuery.ajax({
  // ...other settings...

  xhrFields: {
    withCredentials: true
  }
});

For axios:

axios.post(url, body, {
  withCredentials: true
});

Note that withCredentials is not a header and should be included directly in the request options.

The use of withCredentials is not a factor in determining whether a preflight request is required. Even though
withCredentials can lead to the automatic inclusion of Cookie and Authorization headers on the request they are
not considered to be custom headers for the purposes of the preflight check.

When using withCredentials the server response must include the header Access-Control-Allow-Credentials: true,
otherwise the request will fail the CORS check. This header must also be included on the preflight response, if there is
one.

The use of * values in CORS response headers is also prohibited when using withCredentials. For
Access-Control-Allow-Origin the value of the Origin request header should be used instead but only after it has been
checked to ensure the origin can be trusted. See What are the security implications of CORS? for more information about why
this matters.

While Safari does support withCredentials it tends to have a stricter security policy than other browsers. If you need
to use withCredentials then you should test in Safari sooner rather than later to check whether what you’re trying to
do is actually allowed. For example, to set cookies you will need both origins to share the same domain.

What happens when a CORS request fails?

The most obvious sign that a request has failed due to CORS is an error message in the browser console. This will
usually give a clear indication of why it failed. For more information about CORS error messages in Chrome see our
list of CORS error messages.

It’s important to appreciate that CORS error messages come from the browser, not from the server. The browser applies
the CORS checks to the response headers after a response is successfully received.

A notable exception is the message Reason: CORS request did not succeed, which is shown in Firefox. If you just see
that message then it is possible that the request failed at the network level. For example, you will see that message if
the target server couldn’t be contacted. The message is somewhat misleading as CORS is not really relevant to the
problem. The equivalent message in Chrome doesn’t mention CORS and is the same message that would be shown for a
same-origin request.

The Network section of the browser’s developer tools won’t tell you directly whether the request failed a CORS check,
though that is usually the easiest way to check the relevant headers.

If a CORS preflight OPTIONS request fails then the main request won’t occur.

In some browsers the preflight request won’t be shown separately in the developer tools. Any console errors should make
it clear whether it was the preflight request that failed.

In your JavaScript code all CORS failures will be presented the same way. You’ll see a status code of 0 and you won’t
be able to access the response headers or the response body. You won’t have access to any helpful error messages as
exposing those error messages is regarded as a security risk.

In some cases cookies will be set even though the request failed a CORS check. However, unless the cookie domain is a
match for the current page you won’t be able to access those cookies via document.cookie.

A preflight OPTIONS request is expected to return a status code in the range 200 to 299, otherwise it will fail.
However, the main CORS request can use status codes just like any other AJAX request. A status code that indicates an
error will not cause the CORS checks to fail and, if the CORS checks pass, that status code will be accessible in your
JavaScript code.

Why is CORS so complicated?

How complicated you find CORS depends on your starting point.

If you’re expecting cross-origin requests to be exactly the same as same-origin requests then it will definitely seem
complicated. Unfortunately, the same-origin policy is very much needed, it is not just browser makers worrying about
nothing.

It’s quite likely that your first encounter with CORS was an error message in your browser’s console. Blissfully
ignorant of its significance you probably expected that there’d be a nice, easy fix.

The good news is that CORS does provide a solution. Prior to CORS being introduced you’d have been in real trouble,
fumbling with JSON-P for a bit before giving up and throwing your whole project in the bin.

The bad news is that CORS had to be shoe-horned into the existing design of the web without breaking anything or
introducing significant new security problems.

If you aren’t really familiar with the inner workings of HTTP then CORS may be dragging you into unknown territory. HTTP
headers and OPTIONS requests nicely solve the problem but if you haven’t come across the basic concepts before then
they make the CORS learning curve seem a lot steeper than it actually is.

There are several factors that contributed extra complexity to the design of CORS:

  • Security must be backwards compatible with servers that don’t understand CORS.
  • Special cases have been added to make simple scenarios easier. However, if you want to understand the full picture
    then those special cases are just extra stuff to learn.
  • There was a desire to support browser caching, especially for the preflight request. This is one reason why the
    preflight response requires multiple headers and not just a simple yes-or-no header.

If you’re new to CORS and getting a bit overwhelmed then it may help to reset your expectations. Be patient and allow
yourself some time to find out how CORS works. If you try to rush it you’ll just get lost.

Remember that CORS exists because of very real security concerns. You need to make an informed decision about exactly
how much of that security you want to turn off.

CORS is annoying. Why can’t I turn it off?

Some browsers have command-line options or similar settings to turn off the cross-origin security restrictions. The
details are not included here because this is not something you should be doing, even during development. If you do need
a temporary workaround for development see What are the alternatives to CORS?.

If the web were to be redesigned from scratch it might look very different. But that isn’t going to happen. Instead
browsers have to do the best they can with the web we have today.

Web browsers have to protect their users from malicious sites. You may know that your site isn’t malicious but a
browser doesn’t know that.

For a cross-origin request the browser is trying to protect the other server from your site. It assumes that your site
could be malicious, so it wouldn’t make sense to allow your site to disabled the security protection.

Perhaps you control both servers. As far as you’re concerned they’re both part of the same site. But the browser doesn’t
know that, it just sees two different origins (servers) and has to treat them as totally separate.

Before CORS existed the same-origin policy just blocked cross-origin AJAX requests. Now that was really annoying. At
least with CORS the server can choose to allow the request.

What are the alternatives to CORS?

Before CORS existed there was JSON-P. Now that browser support for CORS is universal there’s no good reason to use
JSON-P instead.

If you just need a solution locally during development then you could try using a browser extension. Typically these
extensions will intercept the server response and inject CORS headers. This may be sufficient in some cases but it’s
not ideal as the requests are still made cross-origin, leading to potential problems, e.g. with cookies.

If you’re trying to contact a publicly accessible server then you could try using CORS Anywhere,
cors-anywhere.herokuapp.com. It acts as a middle-man, adding in the
required headers to get CORS to work. For experiments or demos this might be a satisfactory solution but it’s not a good
idea to use it for a production application.

The other alternative is to use a reverse proxy to channel all requests through a single server. This may be a viable
solution both during development and in production. Cross-origin restrictions don’t apply if the requests all target the
same origin as the current page. The server needs to be configured to pass on relevant requests to the other server.
When the response shows up, it passes that back to the browser. As far as the browser is concerned it’s just talking to
one site.

This might be a good solution but there are some drawbacks to consider:

  • Many hosting solutions will not allow you to configure proxying.
  • As the AJAX requests are now going through your server the load on that server will increase. The network
    infrastructure between the two servers will also have to cope with the extra demand.
  • The total request time will increase.
  • If you are proxying someone else’s site you might be violating the terms and conditions of that site.
  • The other site will see all requests as having come from your IP address. If you make too many requests you may be
    throttled or even blocked.
  • If sensitive data is being transferred then you are now responsible for protecting that data while it passes through
    your server.

I can’t change the server and it isn’t using CORS. What else can I do?

Does using HTTPS have any effect on CORS?

Yes.

Requests from HTTPS

If the page making the request is using HTTPS then the target URL must also be HTTPS. Trying to access resources using
http from an https page is known as mixed content and will be blocked the browser. It won’t even attempt the
request and there should be a clear error message in the console.

Most browsers relax the rules for CORS requests to localhost and 127.0.0.1, so it is possible to make requests
locally using http. This is considered lower risk as the request never actually leaves the user’s device. Safari
currently doesn’t implement this special case and will block any request from https to http.

Requests to HTTPS

If the requesting page has a scheme of http then it can make CORS requests to both http and https URLs.

Invalid SSL certificates, especially self-signed certificates, are a common problem when using CORS. These can result in
requests failing for no apparent reason. For a same-origin request the certificate of the requesting page will be the
same as the requested URL, so any problems with the certificate will have been handled as soon as the page was opened.
For a CORS request the certificate won’t be checked until the request is made, so it fails quietly in the background.

Usually the easiest way to check the certificate is to go directly to the URL in a browser. Even though this won’t be
using CORS it will still be sufficient to check that the certificate is valid. With a self-signed certificate this will
allow you to add an exception so that the certificate will be trusted in future.

Cookies

As of Chrome 80, cookies with SameSite=None must also set the Secure directive. So if you need cross-domain
cookies you’ll need to use HTTPS.

Note that a cookie’s domain is not quite the same thing as origin, so it is possible to have cross-origin cookies
without HTTPS if the domains match.

For more information see Why aren’t my cookies working with CORS?.

Does CORS work with localhost?

Yes. From a CORS perspective localhost and 127.0.0.1 are almost the same as any other domain or IP address.

The server you are attempting to contact may choose to allow requests only from specific origins. CORS itself doesn’t
make a special case for localhost but a server can single out localhost if it so wishes.

Typically localhost is only used during development. This can lead to a perception that localhost is somehow the
cause of a CORS problem. In reality it’s a case of correlation not implying causation. Some more likely causes are:

  1. A bug in the code or CORS configuration.
  2. Caching, making a problem appear to stick around even after it is fixed.
  3. An invalid or self-signed SSL certificate.
  4. Not binding the target server to localhost. Try contacting the server directly to be sure it is accessible
    via localhost.
  5. A browser plugin, debugging proxy or some other piece of development trickery.

Far from localhost having tighter CORS restrictions, in some cases it actually has weaker restrictions (see HTTPS
and Cookies below). This can cause problems in production that didn’t occur during development. To avoid such problems
you may want to consider adding aliases to your hosts file so that you can use URLs during development that are a
closer match to the production URLs.

HTTPS

There is a special case in some browsers for mixed content. If an https page attempts a request to an http page then
this is usually blocked. However, if the target page is using localhost then a CORS request is attempted.

See Does using HTTPS have any effect on CORS? for more information but, in short, if you want to use https for the
requesting page you’ll also need to use https for the target server.

Cookies

Consider this relatively common scenario.

During development you might be running both servers on localhost. Let’s say the UI is hosted at
http://localhost:8080 with a data server at http://localhost:3000.

You open http://localhost:8080 in your web browser and you’re presented with a login page. You enter your username and
password and the page sends a login request to http://localhost:3000. This returns a cookie using the Set-Cookie
header. The request had withCredentials set to true and the cookie seems to work as expected.

When this site reaches production the UI is hosted from http://www.example.com and the data server is at
http://api.example.com. Suddenly the cookies stop working.

The problem is that cookies are tied to a domain. Working locally both localhost:8080 and localhost:3000 are
considered to have a cookie domain of localhost. So even though it was a cross-origin request, from a cookie
perspective it’s considered ‘same site’.

For the production site the cookie’s domain would default to api.example.com, which is not a match for
www.example.com. As they are both subdomains of example.com this can easily be fixed by explicitly setting the
Domain directive on the cookie. However, the key point to note is that production behaves differently from the
development environment.

If you want to know more about working with cookies and CORS see Why aren’t my cookies working with CORS?.

I’ve tried to implement CORS but it isn’t working. What should I do next?

First make sure you’ve understood how CORS works. If you aren’t clear on that then you’ll waste a lot of time trying
to debug any problems.

There are a lot of third-party libraries available that implement CORS for various different types of server. These
can save you some of the work but it is still important to understand how the underlying CORS mechanism works or
you’ll likely run into problems.

If CORS has failed you’ll probably see an error message in your browser’s console. If you don’t see an error message
then check that you don’t have any filters turned on that might be hiding the message.

If you’re seeing a CORS-related error message but you aren’t sure what it means then try consulting our
list of CORS error messages.

The next thing to try is the Network tab of the developer tools. Find the request that isn’t working and
check exactly what is being sent each way.

If you’re seeing an OPTIONS request that you weren’t expecting then see Why am I seeing an OPTIONS request instead of the GET/POST/etc. request I wanted?.

If you’re seeing the warning ‘Provisional headers are shown’ then see Why can’t I access the response headers in Chrome’s developer tools?.

If you think all the headers look correct then you can check them using our CORS header checker.

I’ve configured my server to include CORS headers but they still aren’t showing up. Why?

First check for any error messages in the server logs.

If that doesn’t help, here are some common problems to check:

  • Have you saved the config file?
  • Is the config file in the right place?
  • If you have multiple servers, have you changed the correct one?
  • The server may need restarting. Make sure you restart the correct server.
  • CORS may be configured for some requests but not the request you’re attempting.
  • Is the failing request a preflight OPTIONS request? Does your configuration handle that?
  • Could a proxy or intermediary server be removing the headers?
  • Check for typos in your config. e.g. Spelling (allow / allowed), plural vs singular (headers / header),
    case-sensitivity.
  • If you’re using an online tutorial, is it for a compatible version of the server and/or CORS plugin that you’re using?

One trick that can be useful is to try changing something unrelated in the config file, see whether that works. The
idea is to confirm that the latest version of the config file is definitely being used. Even deliberately breaking the
config file so that the server won’t start is enough to confirm that your changes are having an effect.

Why aren’t my cookies working with CORS?

There are several questions in one here:

  1. How can cookies be set using the Set-Cookie response header using CORS?
  2. Why can’t I see my cookies in the developer tools?. This is so common it gets a separate question in the FAQ.
  3. Can CORS cookies be accessed from JavaScript using document.cookie?
  4. I’ve set the cookies but they aren’t being included on subsequent CORS requests. Why?

There’s a complication that warrants mentioning up front. Cookies are bound to a domain and path, not an origin.
So we’ve actually got two slightly different concepts of ‘same site’ to juggle. Fun times.

Setting a cookie with Set-Cookie

Even if you aren’t using CORS a cookie can disappear because one of its directives is incorrectly set. As that isn’t
relevant to CORS we aren’t going to go into detail here but you should check that directives such as Expires,
Max-Age, Domain, Secure, etc. aren’t set to inappropriate values.

Now let’s consider the case where the domains/origins are totally different. We’ll come back to the muddy waters in the
middle later.

If you’re using XMLHttpRequest to make a CORS request then you’ll need to set the withCredentials flag to true.
For fetch the equivalent setting is credentials: 'include'. For more information on that see
What is withCredentials? How do I enable it?.

Once you’ve set this flag you’ll likely see a number of errors and warnings in your browser’s console. What follows
below is mostly just an explanation of how to fix those errors.

On the server, as well as returning the Set-Cookie and Access-Control-Allow-Origin headers, you’ll also need to
return an extra CORS header to allow credentials:

Access-Control-Allow-Credentials: true

If the request requires a preflight then that must also include this header.

Using credentials disables the * wildcard for the other CORS response headers, so if you’re using that you’ll need to
replace it with explicit values. The most common problems are with Access-Control-Allow-Origin, which will need to
return the exact value of the Origin request header instead of *.

Then there’s the SameSite directive of Set-Cookie to consider. For cross-domain requests it needs to be set to
None or the cookie will be ignored. Note that cross-domain isn’t quite the same thing as cross-origin, we’ll
elaborate on that distinction shortly. In most browsers None is the default value but as of Chrome 80 this is
changing, www.chromium.org.

From February 2020 Chrome will be transitioning the default value to Lax, so SameSite=None will need to be set
explicitly.

As part of the same transition, Chrome will also require that cookies using SameSite=None also use the Secure
directive, which requires https. So if you want to use cross-domain cookies you’re going to need https.

Putting all those headers together we get something like this:

Access-Control-Allow-Origin: example.com
Access-Control-Allow-Credentials: true
Set-Cookie: my-cookie=value; SameSite=None; Secure

Even if you do all this the cookie still won’t be set in Safari, which has tighter security restrictions than other
browsers. There is a workaround though…

At this point we need to go back to those muddy waters around origins and cookie domains.

Let’s consider a website running at http://localhost:8080 making AJAX requests to http://localhost:3000. The ports
don’t match so they have different origins. We’re in CORS territory.

However, a cookie domain is not the same thing as an origin. Cookies for both of these servers will have a domain of
localhost. The port is ignored. So from a cookie-domain perspective they count as the same site.

Keep in mind that cookies were introduced to the web a long time ago. If they were introduced from scratch today they
would likely be designed very differently.

So continuing with our example website running at http://localhost:8080, it has the same cookie domain as
http://localhost:3000. They share a cookie jar. In JavaScript code the cookies will be accessible via
document.cookie, no matter which of the two servers set a particular cookie. The SameSite directive can be set to
None, Lax or Strict — it doesn’t matter because from a cookie perspective they count as the same site. You’ll
still need to use Secure if you want SameSite=None with newer browsers but if both of your servers share a domain
you probably don’t want to be using SameSite=None anyway.

Using a shared cookie domain isn’t limited to localhost but it is a little more complicated once subdomains get
involved. If you have a website running at http://www.example.com making AJAX requests to http://api.example.com
then they won’t share cookies by default. However, a cookie can be shared by explicitly setting the Domain to
example.com:

Set-Cookie: my-cookie=value; Domain=example.com

Even Safari will allow cross-origin cookies to be set so long as they share a cookie domain.

If you’ve read all that and still can’t figure out why your cookies aren’t being set, try using our
CORS header checker to check that you’re setting the response headers correctly. Also take a look at
Why can’t I see my cookies in the developer tools?.

Accessing a cookie with document.cookie

A cookie set via a CORS request can be accessed in JavaScript via document.cookie but only if the cookie’s domain
is a match for the current page. Whether a CORS request was used to set the cookie is not actually relevant.

Including a cookie on a CORS request

Let’s assume that you’ve successfully managed to set a cookie for the correct domain. How do you include that on
subsequent CORS requests to that domain?

The process is quite similar to setting a cookie using CORS. The withCredentials flag must be set to true and the
server will need to return Access-Control-Allow-Credentials: true. As before, wildcards won’t be supported for any
CORS response headers.

Cookies with a SameSite value of Strict or Lax will only be sent if the page domain matches the cookie domain. If
the domains don’t match then SameSite must be None. This is consistent with setting a cookie using CORS so it will
only be a problem if the cookie was set by some other means.

While Safari has tighter restrictions for setting cookies, the rules for including cookies on subsequent requests are
much the same as for other browsers. So while a same-domain request may be required to set the cookie, it can then be
included on a cross-domain request from a different page.

Why can’t I see my cookies in the developer tools?

This is a common misunderstanding.

The developer tools will only show cookies for the current page. Cookies for cross-origin AJAX requests are usually
not regarded as being part of the current page, so they aren’t shown.

Depending on the specifics of your scenario you may see the cookies in the developer tools or you may not. For example,
if you’re running two servers on localhost with different ports then they will share a cookie domain, so the cookies
should show up.

Just because the cookies aren’t shown in the developer tools doesn’t mean that they don’t exist.

To see the cross-origin cookies in the developer tools you’ll need to open another tab with a URL that has the same
domain as the cookie. It doesn’t matter exactly which URL you choose but you should be careful to pick a URL that won’t
change the cookies itself. You’ll also need to open a separate copy of the developer tools for the new tab. You should
then be able to see what cookies are set for that origin.

Alternatively, most browsers provide some mechanism for viewing all cookies. It’s usually hiding somewhere in the
privacy settings. At the time of writing the following URIs will get you to the right place:

  • Chrome: chrome://settings/siteData
  • Firefox: about:preferences#privacy

Of course, the other reason why you may not be able to see the cookies in the developer tools is because no cookies are
being set. See Why aren’t my cookies working with CORS? for more information.

Why can’t I access the response headers in my JavaScript code?

By default, only the following response headers are exposed to JavaScript code for a CORS request:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

These are known as the CORS-safelisted response headers.

The specification was recently changed to add Content-Length to the list of CORS-safelisted response headers. This has
been implemented in some browsers but at the time of writing it still isn’t included in Firefox.

To expose other response headers you need to use Access-Control-Expose-Headers. See
developer.mozilla.org
for more information.

Which CORS response headers go on the preflight response and which go on the main response?

These two headers should be included on both the preflight and the main response:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Credentials

The following headers should only be included on the preflight response:

  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age

The Access-Control-Expose-Headers header should only be included on the main response, not the preflight.

Most of these response headers are optional, depending on the circumstances. The only header that is always required for
a CORS request to succeed is Access-Control-Allow-Origin. For a preflight request, at least one of
Access-Control-Allow-Methods or Access-Control-Allow-Headers will also be required.

Why can’t I see my request in the Network section of the developer tools?

First and foremost check for console errors. The simplest explanation for a missing request is that there’s a bug in
your code and the request didn’t actually happen.

One particularly noteworthy error shown in Chrome is:

Access to XMLHttpRequest at ‘localhost:8080/api’ from origin ‘http://localhost:3000’ has been blocked by CORS policy:
Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

Interestingly, the same problem in Firefox doesn’t show any error message, the request just fails without explanation.

The source of this problem is that the URI is missing the prefix http:// or https://, so the browser interprets the
localhost: as being the scheme of the URI. More information.

However, assuming you aren’t seeing that particular error…

In most browsers the developer tools must be open before you make the request, otherwise it won’t be recorded.

Check you don’t have any filters turned on which could be hiding your request.

In Safari and older versions of Chrome you won’t be able to see the preflight OPTIONS request as a separate request.

Preflight OPTIONS requests can also be cached, so it’s possible you may not see the request you’re expecting because a
cached response has been used instead. If you have access to the server logs you may be able to confirm what requests
were actually received.

It can be useful to check across multiple browsers. Using a new Incognito/Private window can also help to bypass any
caching problems that might be interfering with your requests.

Why can’t I access the response headers in Chrome’s developer tools?

When you try to access the headers via the Network tab of Chrome’s developer tools you may see the warning:

Provisional headers are shown

Further, the context-menu for the request won’t show the options to Copy request headers or
Copy response headers.

There are several possible causes for this warning, some of which are not directly related to CORS. It may just mean
that the request hasn’t finished yet because the server is taking a long time to respond. It’ll also be shown if you try
to access files directly off the file-system without using a web-server.

However, the most likely cause for a CORS request is that the preflight checks are failing. If the preflight OPTIONS
request fails then the main request won’t even be attempted, so there are no headers to show. There should be a
corresponding error message in the browser’s console.

How do the Authorization and WWW-Authenticate headers work with CORS?

The Authorization request header can be set as a custom header on a request and, just like any other custom header, it
would trigger a preflight OPTIONS request.

However, a bit like the Cookie header, the Authorization header can also be included automatically by the browser as
part of HTTP authentication. Ignoring the cross-origin aspect for a moment, the steps for this form of authentication
are:

  • The browser requests a URL.
  • The server responds with a 401 status code and a WWW-Authenticate header indicating the authentication scheme to
    be used.
  • The browser prompts the user for credentials.
  • The original request is retried with the credentials encoded into the Authorization header.
  • Subsequent requests to the same URL will automatically included the Authorization header.

For cross-origin requests the withCredentials flag must be set to true. In most browsers that should enable HTTP
authentication, the exception being Safari.

If the withCredentials flag is not set, or the user does not provide credentials, then the original 401 response will
be the response exposed via JavaScript.

If a preflight OPTIONS request is required then this must succeed without any authentication.

Oddly, the 401 response does not need to include the Access-Control-Allow-Credentials header for the browser to
prompt for credentials. However, it should be included anyway in case the user declines the credentials prompt. In that
scenario the 401 becomes the exposed response and then Access-Control-Allow-Credentials is required.

How can I include authorization headers on the preflight OPTIONS request?

You can’t. The server must be configured to respond to the preflight OPTIONS request without any authentication
headers being present.

If you’re using a filter or middleware layer on the server to block all unauthorized requests then you’ll need to
provide an exception for the preflight OPTIONS requests.

Does CORS support HTTP redirects?

Yes. CORS requests do support HTTP redirects so long as all the requests include the relevant CORS response headers.

When we say ‘HTTP redirects’ we mean using status codes such as 301, 302, 307 or 308 in conjunction with a
Location response header. For a typical AJAX request these redirects are performed automatically by the browser
without any explicit handling in client-side JavaScript.

The specification for CORS has gradually become more permissive towards redirects. The information presented here
reflects what is currently implemented in browsers but it is likely to continue to change.

A preflight OPTIONS request must not attempt a redirect. Instead the preflight should just return the usual response
headers required for the CORS checks to pass. The redirect can then be performed on the main request.

A potentially problematic scenario occurs if the redirect is to a URL with a different origin from the URL that was
originally requested. This is allowed but when the browser attempts the new request it will set the Origin header to
null. This is not a bug, it is a security precaution included by design.

Even if you aren’t intentionally using redirects there are two common ways that they can creep in:

  1. Redirecting from http to https.
  2. Redirecting to add or remove a trailing URL slash. e.g. A server may redirect http://example.com/api/users to
    http://example.com/api/users/ or vice-versa.

If not done correctly this can change the request method to GET, which can trigger other errors such as a 405
response from the server. Inadvertently changing to a GET request will also cause the request body to be dropped.

Often the simplest solution is to use the final URL instead and skip the redirect altogether.

Why is my Origin ‘null’?

Under some circumstances the request header Origin can be set to the special value null.

Note that this is the 4-character string "null", not to be confused with the null keyword used by many programming
languages.

Within the browser the value of location.origin can also be the string "null".

This special value is used whenever a proper origin value doesn’t exist or can’t be exposed for security reasons. The
request header may be null even if location.origin has a proper value.

Some examples:

  • If the page is being loaded directly off the file-system using the file: scheme, without a web-server, it is still
    allowed to make HTTP requests but the Origin header will be null.
  • Likewise, a page created using the data: scheme will have a null origin. e.g. <iframe src="data:text/html,...">.
    Here the ... would be the URI-encoded contents of a web page to show in the iframe. The web page inside the
    iframe would have a null origin.
  • An iframe using sandboxing, such as <iframe src="..." sandbox="allow-scripts">. Within the iframe the value of
    location.origin may be populated based on the src URL but any CORS requests will have a null origin.
  • An HTTP redirect on a CORS request that changes the target origin. Even if the original request had a proper Origin
    header the redirected request will have Origin: null.

It is still possible for null to pass a CORS check, just like for any other Origin value:

Access-Control-Allow-Origin: null

It has been suggested that the specification should be changed to prevent null matching itself, so it is possible this
may stop working in future. As there are many different ways for Origin to be null it is quite difficult to target a
specific case on the server. The Referer header may still be available in some cases as a hint to what the Origin
would have been but that isn’t reliable either. Generally it is recommended not to allow access from null origins
explicitly, though Access-Control-Allow-Origin: * can be used for genuinely open resources.

What are the security implications of CORS?

It’s almost impossible to provide a comprehensive list but here are some of the common concerns.

Yes, they can.

This kind of attack has always been possible, even with servers that don’t use CORS. The defence against these attacks
is typically two-fold:

  1. Authentication and authorization checks to ensure the user sending the request is allowed to make the request.
  2. Validation and/or sanitization of all the data on the request to ensure it’s in an acceptable form.

Relying on a UI or web browser to perform these checks isn’t sufficient, they need to be on the server.

So what’s the point of CORS if it can easily be bypassed?

CORS aims to stop someone making a request while pretending to be someone else.

Let’s say you open a webpage in your browser. The page you open is malicious: someone has put some JavaScript code into
the page that is trying to cause trouble. It fires off some HTTP requests to other websites pretending to be you. There
are two main varieties of mischief that it may try to inflict:

  1. Stealing data. e.g. It might send a request to your webmail and grab a copy of your emails.
  2. Changing data. e.g. Deleting the contents of your database or transferring money from your bank account or buying
    something on your behalf from an eCommerce site.

The Access-Control-Allow-Origin response header is primarily concerned with the first problem, stealing data. At the
network level the data is still transferred but if the Access-Control-Allow-Origin header doesn’t allow the current
origin then the malicious script can’t read the response.

For the second problem CORS has preflight requests. The potentially harmful request won’t even be attempted unless the
preflight allows it.

It is important to appreciate that a ‘malicious site’ may not have started out as malicious. You may have even created
it yourself. The problem is XSS vulnerabilities, which allow hackers to inject their own code into the site. When you
enable CORS to allow requests from other sites you aren’t just trusting the sites’ developers not to be malicious,
you’re also trusting them not to have any XSS vulnerabilities that leave your server exposed.

Hmmm. That raises more questions than it answers. For starters, how does this malicious site pretend to be me?

There are several options here.

The most obvious answer is cookies. If you’ve logged into a site and it uses cookies to identify you then those
cookies will be included by the browser on all requests to that site. The malicious script doesn’t need direct access to
the cookies, it just makes a request and the browser includes the cookie automatically.

This type of browser magic falls under the heading of ambient authority. The withCredentials flag is used to control
three types of ambient authority:

  1. Cookies.
  2. The Authorization header as part of HTTP authentication. This shouldn’t be confused with using the Authorization
    header explicitly as a custom request header, which is not ambient authority. See
    How do the Authorization and WWW-Authenticate headers work with CORS? for more information.
  3. TLS client certificates.

These forms of ambient authority could have been left out of CORS altogether and some initial implementations didn’t
allow them. However, enough developers wanted cookie support that the current compromise was eventually included.

If you’re using cookies and don’t need to support cross-origin requests then you should consider setting the directive
SameSite to either Strict or Lax. Browsers are gradually switching to Lax by default, away from the historical
default of None, but you don’t need to wait if you set it explicitly.

There are other forms of ambient authority that are less easy to avoid and which pose very real problems to the design
of CORS.

For example, a site could use IP addresses or network layout to prevent unauthorized access.

A common scenario is a site hosted on an internal network that allows access to anyone on that network. The ‘security’
here assumes that the site isn’t accessible outside the local network. An external hacker can’t send HTTP requests
directly to the server. However, if someone on the internal network opens the hacker’s malicious site then it can start
sending requests to those internal sites from within the browser. The page running in the browser is being used as a
bridge between the internal network and the outside world.

Router configuration pages are a particularly common example. Chances are your home internet connection includes a
router with a webpage to configure your home network.

For the ‘stealing data’ problem, why not just return an empty response instead?

For a new server you could do precisely that. However, CORS had to be designed to work with servers that already existed
and had no knowledge of CORS. Those servers won’t have the relevant response headers so the browser will prevent access
to the response.

The response in that scenario still makes it to the browser and would be accessible in the developer tools. That isn’t a
problem as the developer tools are only accessible to the person using the device. CORS isn’t trying to protect the data
from that person. Quite the opposite, that person is the potential victim of the data theft. CORS is trying to stop a
malicious script embedded in the page from accessing the response and passing it on to someone else.

Not all requests use a preflight. Doesn’t this leave the door wide open to the hackers in cases where they don’t need access to the response?

Yes, it does.

However…

It is a door that was already open before CORS was introduced. This particular vulnerability goes by the name CSRF (or
XSRF), which stands for cross-site request forgery.

Historically a CSRF attack could be performed in various ways but the most interesting is probably an HTML <form>.
Such a form could be submitted via a POST request from the malicious site to pretty much anywhere. The same-origin
policy did not prevent form submissions, it just prevented the source page from accessing the response.

Roughly speaking, the requests that don’t need a preflight are the same requests you could make using a <form>
instead.

While this is a security hole, it’s a hole that has existed for a long time and techniques have been developed to
protect against it. CORS just tries not to make the hole any bigger.

The withCredentials flag doesn’t trigger a preflight. Wouldn’t it be safer to always use a preflight check with cookies?

It would. But, again, CORS isn’t introducing any new security holes here. It’s just retaining the holes that already
existed with HTML forms.

The gradual shift by browsers towards defaulting to SameSite=Lax should help to protect cookies from CSRF abuse going
forward.

Why is a * value for Access-Control-Allow-Origin not allowed when using withCredentials?

The reasoning goes something like this:

  1. A * value exposes the content to any other webpage that wants it. This includes potentially malicious pages.
  2. If the content is always the same, no matter who requests it, then exposing it to everyone isn’t necessarily a
    problem.
  3. However, if the request requires withCredentials to be set then the content isn’t the same for everyone. Either
    access is restricted or the content varies by user. In this scenario the malicious page is now in a position to steal
    the version of the content that’s accessible to the current user.

Unfortunately, yes you can. Some libraries will even do this for you.

This is just as bad as using *. The only reason CORS doesn’t prevent it is because it can’t. There’s no way for the
browser to know that your server is indiscriminately echoing back the Origin header.

To be clear, there’s nothing wrong with echoing back the Origin header for specific, trusted origins. That’s precisely
how CORS is supposed to work. The problems arise when there aren’t adequate restrictions on the origins that are
allowed.

If you’re returning Access-Control-Allow-Credentials: true then you shouldn’t be echoing back all origins in
Access-Control-Allow-Origin. Chances are you have a gaping security hole. Worse, as discussed earlier, hosting your
site behind a firewall on an internal network is unlikely to protect you.

If I can’t use *, is there a way to allow all subdomains, e.g. *.example.com?

The CORS specification doesn’t allow for this. Only the exact value * is special and it can’t be used as a wildcard in
other values.

Configuring a server to echo back all origins for a particular domain can be quite tricky to get right. Consider the
following examples of origins:

http://example.com
https://www.example.com
http://evil-site-example.com
http://example.com.evil-site.com

We might want to support the first two origins, including http, https and all subdomains, but without matching the
other two. Those other two origins have example.com as a substring but they are totally unrelated domains that could
be under the control of anybody. Further, configuration based on regular expressions needs to be careful to escape the
. character to avoid it being treated as a wildcard.

You might think that no-one is going to bother attacking your site because it’s small and not worth the effort.
Unfortunately these exploits can easily be found just by using scripts that trawl the web looking for vulnerable sites.
These hackers (usually script kiddies) aren’t trying to attack your site specifically, they just set the script
running and wait for it to find a victim.

There’s also a problem with the premise of this question. You probably shouldn’t be trying to allow access to all
subdomains in the first place. If it isn’t possible to list all the relevant subdomains explicitly then it probably
isn’t safe to trust them all either. If any subdomain is running an application with an XSS vulnerability then it could
potentially be compromised.

I read somewhere that Access-Control-Allow-Origin: null is potentially insecure. Why?

If you aren’t familiar with the special origin value null then see Why is my Origin ‘null’?.

Part of the problem is that some developers mistakenly believe that returning null is equivalent to omitting the
header altogether. A bit of basic testing may even seem to confirm that.

The reality is that returning Access-Control-Allow-Origin: null will allow any request with Origin: null.

Generally you can’t set the Origin header in your client-side code, the browser will set it for you. However, it’s
relatively easy to use iframes or HTTP redirects to coerce the browser into sending Origin: null. So if you allow
requests from null you’re effectively allowing them from anywhere.

As we’ve already discussed, allowing requests from anywhere is fine under certain circumstances. However, in those
circumstances you can just use Access-Control-Allow-Origin: * instead.

Where can I read more about the security implications of CORS?

You might find these useful:

  • w3c.github.io
  • portswigger.net

What is an opaque response?

If you’re using the fetch API then you might have come across this message in Chrome:

If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

It’s shown at the end of some CORS error messages.

The first thing to appreciate is that disabling CORS does not mean disabling the same-origin policy. It is
important to be clear about the difference between the two.

An opaque response is an HTTP response where you can’t access any of the details in your JavaScript code. It is opaque
in the sense that you can’t look into it. That includes the status code, the headers and the body content. You may
notice that it’s very similar to what happens when a response fails the CORS checks.

To make a fetch request with an opaque response set the mode to 'no-cors':

fetch(url, {
  mode: 'no-cors'
}).then(response => {
  console.log(response.type) // logs the string 'opaque'
})

Some notes:

  • The mode is only relevant for a cross-origin request, it doesn’t matter for same-origin requests.
  • Any CORS response headers will be ignored. Even if they are included you won’t be able to read the response.
  • A GET request won’t include the Origin request header. It will still be included for POST requests, just like it
    would for same-origin requests.
  • Only simple requests that do not require a preflight are allowed.
  • There is no equivalent if you’re using XMLHttpRequest.

A request made using mode: 'no-cors' won’t undergo CORS checks in the browser, so the usual CORS error messages won’t
be shown. But other than suppressing the error messages, what use is it?

In practice the use cases are pretty limited, so if you’re seeing the error message mentioned earlier it is unlikely to
be the solution you want.

One use case is for requests where you handle success and failure exactly the same way. You try to tell the server to do
something but whether or not it succeeds doesn’t have any impact on the UI.

Another use case is caching. The requests can be used to pre-populate caches for things like stylesheets where you don’t
need to access the response details in JavaScript code.

You can suggest improvements to this page via
GitHub.

CORS errors

Совместное использование ресурсов между источниками ( CORS ) — это стандарт, который позволяет серверу ослабить политику одного источника . Это используется для явного разрешения одних запросов из разных источников при отклонении других. Например, если сайт предлагает встраиваемую услугу, может потребоваться ослабить определенные ограничения. Настроить такую ​​конфигурацию CORS не обязательно просто и могут возникнуть некоторые проблемы. На этих страницах мы рассмотрим некоторые распространенные сообщения об ошибках CORS и способы их устранения.

Если конфигурация CORS настроена неправильно, в консоли браузера будет отображаться сообщение об ошибке типа "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at $somesite" что указывает на то, что запрос был заблокирован из-за нарушения безопасности CORS. правила. Однако это не обязательно может быть ошибкой настройки. Возможно, что запрос на самом деле намеренно запрещен веб-приложением пользователя и удаленной внешней службой. Однако, если конечная точка должна быть доступна, для успешного выполнения потребуется некоторая отладка.

Выявление проблемы

Чтобы понять суть проблемы с конфигурацией CORS,необходимо выяснить,в каком запросе ошибка и почему.Эти шаги могут помочь вам в этом:

  1. Перейдите на нужный веб-сайт или веб-приложение и откройте Инструменты разработчика .
  2. Теперь попробуйте воспроизвести неудачную транзакцию и проверьте консоль , если вы видите сообщение об ошибке нарушения CORS. Вероятно, это будет выглядеть так:

Firefox console showing CORS error

Текст сообщения об ошибке будет похож на следующий:

Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at https://some-url-here. (Reason:
additional information here).

Примечание. По соображениям безопасности подробности о том, что пошло не так с запросом CORS , недоступны для кода JavaScript . Код знает только то, что произошла ошибка. Единственный способ определить, что именно пошло не так, — это посмотреть подробности в консоли браузера.

сообщения об ошибках CORS

See also

  • Glossary: CORS
  • CORS introduction
  • Настройки CORS на стороне сервера
  • CORS включенное изображение
  • атрибуты настроек CORS
  • https://www.test-cors.org — страница для тестирования запросов CORS.


HTTP

  • CORS

    Cross-Origin Resource Sharing (CORS)-это механизм,основанный на HTTP-заголовках,который позволяет серверу указывать любое происхождение (домен,схема,порт),отличное от его происхождения.

  • Заголовки ответа HTTP

    В этом разделе перечислены заголовки HTTP-ответов,которые серверы возвращают для запросов контроля доступа,определенных спецификацией Cross-Origin Resource Sharing.

  • Errors: CORSAllowOriginNotMatchingOrigin

    Происхождение,делающее запрос,не соответствует разрешенному заголовком Access-Control-Allow-Origin.

  • Errors: CORSDidNotSucceed

    HTTP-запрос,использующий CORS,завершился неудачей из-за сбоя соединения на уровне сетевого протокола.

Andy Potts

Andy Potts

Posted on Jul 23, 2020

• Updated on Jul 31, 2020

• Originally published at Medium

When developing a website/web app on localhost which makes requests to another server, you might run into Cross Origin Resource Sharing (CORS) issues. I won’t go into too much detail about what CORS is in this post. All I will say is that CORS exists for security reasons, but when you’re developing locally it can be a pain! You can read more about CORS on the MDN docs.

I have written this simple guide to explain the main solutions for disabling cross origin restrictions on localhost (and therefore fixing any CORS errors whilst developing your app locally), which I will explain in more detail below.


1. Use the proxy setting in Create React App

Create React App comes with a config setting which allows you to simply proxy API requests in development. This is available in react-scripts@0.2.3. To do this add the proxy setting to your package.json like this

"proxy": "https://cat-fact.herokuapp.com/",

Now when you make an API request to https://localhost:3000/api/facts Create React App will proxy the API request to https://cat-fact.herokuapp.com/facts and the CORS error will be resolved. 

This is a really simple solution which might not work with more complicated situations where multiple API’s are involved, or certain types of API authentication is needed.

2. Disable CORS in the browser

You can directly disable CORS in the browser. If you do this, please be aware that you are disabling security restrictions which are there for a reason. I wouldn’t recommend browsing the web with CORS disabled; Just disable it whilst developing your website/app.

Chrome:

The most reliable way to disable CORS in the latest version of Chrome on Mac (tested on v84) is to run it with web security disabled.

  1. Force quit Chrome by going to the mac menu and pressing “force quit” (or pressing command Q).
  2. Then run this command to open Chrome with web security disabled
open -n -a /Applications/Google Chrome.app/Contents/MacOS/Google Chrome — args — user-data-dir=”/tmp/chrome_dev_test” — disable-web-security

Once you’re done developing, restart Chrome and it will go back to normal.

Firefox:

The easiest and most reliable way to disable CORS in Firefox is to install the CORS Everywhere plugin.

Safari:

The easiest and most reliable way to CORS in Safari is to disable CORS in the develop menu.

  1. Enable the develop menu by going to Preferences > Advanced.
  2. Then select “Disable Cross-Origin Restrictions” from the develop menu.

Once you’re done developing, restart Safari and it will go back to normal.


3. Use a proxy to avoid CORS errors

Alternatively you could use a proxy like cors-anywhere.
If you want to easily demo cors-anywhere, Rob — W has setup a public demo which is great for consuming public API’s as it requires no registration or config https://cors-anywhere.herokuapp.com. As it’s just a demo, requests are limited.

To use the public demo of cors-anywhere, just add the url you want to make the request to after the domain e.g. https://cors-anywhere.herokuapp.com/https://cat-fact.herokuapp.com/facts (*if you view this in the browser you might get an error about a missing request header. When you make an API request using in your app using something like Axios or Fetch this won’t be an issue).


If you found this useful, have any questions, or want more content like this, feel free to follow me on twitter!

Понравилась статья? Поделить с друзьями:
  • Flashtool error status sec auth file needed
  • Firedac phys sqlite error no such table
  • Flashtool error status brom cmd send da fail 0xc0060003
  • Firedac phys sqlite error database is locked
  • Flashtool error 4032