CORS is acronym for cross origin resource sharing. Cross-origin resource sharing (CORS) is a browser mechanism which enables controlled access to resources located outside of a given origin. Many websites interact with subdomains or third-party sites in a way that requires cross-origin access. A controlled relaxation of the same-origin policy is possible using cross-origin resource sharing (CORS). Note that XMLHttpRequest and fetch follow same orgin policy and without CORS , scripts running on a browser client to cannot interact with resources from a different origin.
To understand it is important to understand what is a cross origin request. Read https://clarifyforme.com/posts/5637618884673536/What-is-a-cross-origin-request . Also do not confuse between same site and same origin. same site is a cookie attribute which determine how will browser handle cookies in cross site requests. Read https://clarifyforme.com/posts/5177685533786112/what-is-the-difference-between-site-and-origin
For security reasons, the browser applies same origin policy to scripts. ie cross origin http requests from scripts are blocked. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own origin. (cross origin links etc are not forbidden) hence for cross origin script requests to work, CORS(cross origin resource sharing) header origin has to be part of request and this origin must be in the whitelist of destination. Hence for CORS usually here are the steps. Lets assume xhr cross origin request is made say from script running in a.com to b.com
- If the request is a non simple request browser sends a "data-less","automatic" "preflight" OPTIONS request, to verify first that the domain and verb are supported by server .If the result of the preflight call dictates that the request cannot be made, the actual request to the server will not be executed. The preflight response also lists permissible non-simple headers and methods (included in Access-Control-Allow-Headers,Access-Control-Allow-Method respectively) . For instance the server may not want to support delete method in cross origin xhr request. .The request is non simple request if one or all of following condtions are true
- The HTTP request is neither GET nor POST nor HEAD
- A header other than CORS safe-listed header is used. : the only CORS safe listed headers are Accept,Accept-Language,Content-Language ,Content-Type (this is only simple when its value is application/x-www-form-urlencoded, multipart/form-data, or text/plain)
- Event listeners are registered on any XMLHttpRequestUpload object
- ReadableStream object is used in the request.
- Typically headers sent along with preflight request are
- Origin : the script's current origin
- Access-Control-Request-Headers : The Access-Control-Request-Headers request header is used by browsers when issuing a preflight request to let the server know which HTTP headers the client will send when the actual request is made . The browser simply reads the headers from actual request and generates the value of this header(preflight is auto generated by browser) .The complementary server-side header of Access-Control-Allow-Headers will answer this browser-side header.
- Access-Control-Request-Method : The Access-Control-Request-Method request header is used by browsers when issuing a preflight request, to let the server know which HTTP method will be used when the actual request is made. (If the actual method is put then the value of this header will be put). This header is necessary as the preflight request is always an OPTIONS and doesn't use the same method as the actual request.
- for example a preflight request may look this.
- OPTIONS /somePage HTTP/1.1
- Origin: http://siteA.com
- Access-Control-Request-Method: PUT (the method of acutal request)
- Access-Control-Request-Headers: Content-Type (the headers which are part of actual request)
- This above request basically says "I would like to make a PUT request with the Content-Type and Accept headers from http://siteA.com - is that possible?".
- Note that Access-Control-Request-Method and Access-Control-Request-Headers are added by the browser automatically.
- The preflight request response may come with the following headers
- Access-Control-Allow-Origin: http://siteA.com
- Access-Control-Allow-Methods: GET, PUT
- The Access-Control-Allow-Methods response header specifies one or more methods allowed when accessing a resource in response to a preflight request.
- Access-Control-Allow-Headers: Content-Type , Custom-HeaderA,Custom-HeaderB
- The Access-Control-Allow-Headers response header is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request.
- Access-Control-Max-Age: The maximum duration that the response to the preflight request can be cached before another call is made
- (with this headers the server responds :: I allow cross origin script request from siteA.com with http methods GET , PUT and the headers Content-Type,Custom-HeaderA,Custom-HeaderB)
- The preflight response would then be examined by the browser to decide whether to continue with the request or to abandon it.
- For instance if the request is PUT request and PUT is not found in Access-Control-Allow-Methods then the actual request will not be made.
- In case the actual request has a custom header you may get a "not allowed by Access-Control-Allow-Headers in preflight response" exception . In this situation, you need to set up the Access-Control-Allow-Headers in your response header at server side.
- The acutal request is conditinally made after the preflight request .
- The actual request will be made with request header "origin" . This header will contain the origin of the request. In this case https://a.com:443 . By default, Site B's pages are not accessible to any other origin.
- The response must contain the following
- Access-Control-Allow-Origin.
- The value can be * (b.com essetially says i will allow cross site xhr requests from any site,effectively disabling the same origin policy).
- * should only be used for public APIs.
- * prevents sending credentials like cookies in requests. ie If you require the client to pass headers (like cookies) the value can not be * — it must be a fully qualified domain! . (note:- this is not true for background scripts running in chrome plugins).Attempting to use the wildcard with credentials results in an error. The error message will be Reason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'. To solve this issue If the request is being issued using XMLHttpRequest, make sure you're not setting withCredentials to true. (ie make sure cookies do not go). The reason why this is done is, if you have disabled the same origin policy by allowing all origins, this is still ok for content which requires unauthenticated access but for content which requires authenticated access you cannot simply disable same origin policy.
- If this header is missing , you will get error : Reason: CORS header 'Access-Control-Allow-Origin' missing
- To allow any site to make CORS requests without using the * wildcard (for example, to enable credentials), your server must read the value of the request's Origin header and use that value to set Access-Control-Allow-Origin, and must also set a Vary: Origin header to indicate that some headers are being set dynamically depending on the origin. Again this should be done only for public API.
- The value can be https://a.com (b.com essetially says i will allow cross site xhr requests a.com only).
- It should be noted that if there is no preflight request(simple request) then acutal request will go . If Site A requests a page from Site B, the browser will actually fetch the requested page on the network level and check if the response header Access-Control-Allow-Origin lists Site A as a permitted requester domain. If Site B has not indicated that Site A is allowed to access this page, the browser will trigger the XMLHttpRequest's error event and deny the response data to the requesting JavaScript code.
- The specification for the Origin header supports the value null. Browsers might send the value null in the Origin header in various unusual situations like cross origin redirect.Some applications might whitelist the null origin to support local development of the application.In this situation, an attacker can use various tricks to generate a cross-origin request containing the value null in the Origin header. This will satisfy the whitelist, leading to cross-domain access.
- The value can be * (b.com essetially says i will allow cross site xhr requests from any site,effectively disabling the same origin policy).
- Access-Control-Allow-Origin.
- The response can optinally contain following headers
- Vary header: If the server sends a response with an Access-Control-Allow-Origin value with an explicit origin then the response can also include a Vary response header with the value Origin (Vary: Origin) to indicate to browsers that server responses can differ based on the value of the Origin request header.
- Access-Control-Allow-Credentials. By default, cross origin xhr request does not include cookies . In order to reduce the chance of CSRF vulnerabilities in CORS, CORS requires both the server and the client to acknowledge that it is ok to include cookies on requests.
- client side: The XMLHttpRequest.withCredentials property is a boolean value that indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.In addition, this flag is also used to indicate when cookies are to be ignored in the response. The default is false. Note that this is true regardless of Access-Control- header values.server side.The client code must set the withCredentials property on the XMLHttpRequest to true in order to give permission.However, this header alone is not enough.
- The server : The server must respond with the Access-Control-Allow-Credentials header. Responding with this header to true means that the server allows cookies (or other user credentials) to be included on cross-origin requests from this origin.
- Note that the cookies will go in a cross site request based on SameSite attribute.
FAQ
Questions) Is CORS a protection against CSRF?
Answer ) No. Infact CORS is controlled relaxation of same origin policy. Poorly configured CORS lead to security risks. CSRF attack can be prevented via SameSite attribute of cookies and CSRF tokens.
Questions) Can CORS lead to xss attack?
Answer) yes, If a website trusts an origin that is vulnerable to XSS attack then an attacker could exploit the XSS to inject some JavaScript that uses CORS to retrieve sensitive information from the site that trusts the vulnerable application.
Questions) Can a website trust an origin that is on http?
Answer) no,
Questions) Cross origin javascript is not able to access resouce but i am able to acccess it through a program.
Answer ) CORS is a feature implemented by the browser. Hence CORS config won’t prevent non-browser stuff from successfully retrieving your resources.
Read more/References
1. read this excellent stack over flow post : https://stackoverflow.com/questions/15726423/how-does-cors-provide-at-least-some-security-to-users
2. https://stackoverflow.com/questions/10636611/how-does-access-control-allow-origin-header-work