Cross-Origin Resource Sharing: Difference between revisions
Line 62: | Line 62: | ||
Host: B.com | Host: B.com | ||
Access-Control-Request-Method: GET | Access-Control-Request-Method: GET | ||
Origin: http | Origin: http://A.com | ||
Referer: http | Referer: http://A.com/the-page-containinig-js.html | ||
If B.com wants to allow cross-origin calls, it should respond with a pair of headers: | If B.com wants to allow cross-origin calls, it should respond with a pair of headers: | ||
Access-Control-Allow-Origin: http | Access-Control-Allow-Origin: http://A.com | ||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE | Access-Control-Allow-Methods: GET, POST, PUT, DELETE | ||
Revision as of 01:59, 18 November 2018
External
- https://en.wikipedia.org/wiki/Same-origin_policy
- https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
- https://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
- http://www.w3.org/TR/access-control/
- RFC 6454 https://tools.ietf.org/html/rfc6454
Internal
TODO
See how swagger-generated code implements in io.swagger.api.ApiOriginFilter
:
package io.swagger.api;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JaxRSServerCodegen", date = "2015-09-18T16:59:22.303Z")
public class ApiOriginFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
public void destroy() {}
public void init(FilterConfig filterConfig) throws ServletException {}
}
Overview
Web browsers are built so they don't allow JavaScript that runs as part of web page to make HTTP requests via the XMLHttpRequest interface to other sites than the origin web site. In some cases - Chrome, for example, the HTTP request is made, but the browser will just throw out the response and log a JavaScript error:
XMLHttpRequest cannot load http://b.com/B.html. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://a.com' is therefore not allowed access.
The same-origin policy only applies to web fonts and AJAX (XMLHttpRequest) requests. A web page may freely embed images, stylesheets, scripts, iframes, videos and some plugin content (such as Adobe Flash) from any other domain.
Why?
A possible explanation is that the web browser wants to prevent the situation when an unknowing user downloads malicious behavior from a web site A, which then starts to make invocations into other site B. In order for this to be allowed, site B has to explicitly allow it - and then the browser allows it too. The browser insures this by essentially asking B: "Do you allow scripts downloaded from A to invoke into you?" This invocation is called "pre-flight".
Cross-Origin Resource Sharing
Cross-origin calls can be made with the cooperation of the second server. The standard way to do it is to employ Cross-Origin Resource Sharing (CORS), which is a standardized technique. See Cross-Origin Resource Sharing http://www.w3.org/TR/access-control. It consists of a simple header exchange between the client and the second server. This standard extends HTTP with a new Origin request header and a new Access-Control-Allow-Origin response header.
The way the standard is supposed to work is the following:
A browser rendering content from http://A.com wants to send a request into http://B.com so it “pre-flights” the request by inquiring the B.com server on its capabilities with an Origin header sent over an OPTIONS request:
OPTIONS / HTTP/1.1 Host: B.com Access-Control-Request-Method: GET Origin: http://A.com Referer: http://A.com/the-page-containinig-js.html
If B.com wants to allow cross-origin calls, it should respond with a pair of headers:
Access-Control-Allow-Origin: http://A.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE
To allow general access, the second server could respond with:
Access-Control-Allow-Origin: *
Origin
The origin is defined by {protol, host, port}. The algorithm to calculate the origin of a URI is specified in RFC 6454 https://tools.ietf.org/html/rfc6454/
Behavior in Presence of Custom Headers
If the cross call contains custom headers, the browser includes those custom headers in the pre-flight invocation:
OPTIONS /blah HTTP/1.1 Host: B.com Access-Control-Request-Method: GET Origin: http://A.com Access-Control-Request-Headers: onecloud-adgroup, onecloud-user Referer: http://A.com/the-page-containinig-js.html
Note "Access-Control-Request-Headers".
B.com must acknowledge the headers, otherwise we get an error message similar to:
XMLHttpRequest cannot load http://B.com/blah/. Request header field OneCloud-User is not allowed by Access-Control-Allow-Headers in preflight response.
Acknowledgement is provided by returning an "Access-Control-Allow-Headers" header listing the comma-separated list of allowed headers:
Access-Control-Allow-Headers: Apples, Oranges
Cross-Site Request Forgery (CSRF)
Cookie-to-Header Token.
Web applications that use JavaScript for the majority of their operations may use an anti-CSRF technique that relies on same-origin policy:
1. On login, the web application sets a cookie containing a random token that remains the same for the whole user session
Set-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/
2. JavaScript operating on the client side reads its value and copies it into a custom HTTP header sent with each transactional request
X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
The server validates presence and integrity of the token