Tuesday, October 16, 2018

Basics of CORS (Cross-Origin Resource Sharing)

Before learning more about CORS, it's important to familiarize yourself with SOP (Same-Origin Policy).

What Is SOP (Same-Origin Policy)?

SOP is a security mechanism implemented in almost all of the modern browsers. It does not allow documents or scripts loaded from one origin to access resources from other origins. Now, what is the origin? The origin is not only domain. — the origin could be the combination of the Host name, Port number, and URI (Uniform Resource Identifier) Scheme.

Why Is SOP Important?
For any HTTP request to a particular domain, browsers automatically attach any cookies bounded to that domain.

It doesn't matter if a request originates from "your-bank.com" or "malicous.com." As long as the request goes to your-bank.com, the cookies stored for your-bank.com would be used. As you can see, without the Same-Origin Policy, a Cross-Site Request Forgery (CSRF) attack can be relatively simple, assuming that authentication is based solely on a session cookie. That’s one of the reasons the SOP was introduced.

What Is CORS?

For security reasons, SOP is implemented in all latest browsers, and because of that, a website from one origin cannot access resources from a foreign origin, and to make that possible, CORS comes into the picture. In short, CORS is standard of sharing cross-origin resources. This allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served.
The client and server exchange a set of headers to specify behaviors regarding cross-domain requests.

Examples of Access Control Scenarios

Simple Request

  • The simple request is that the request that doesn't trigger a CORS preflight
  • The only allowed HTTP methods are: GET, HEAD, POST
  • The only allowded values for the 'Content-Type' header are:
    1. application/x-www-form-urlencoded
    2. multipart/form-data
    3. text/plain
For example, suppose the web content on the domain http://a.com wishes to invoke content on the domain http://b.com. The code of this sort might be used within JavaScript deployed on http//a.com:


Let us look at what the browser will send to the server in this case, and let's see how the server responds:
1. The request from "http://a.com" is sent to the other server, "http://b.com," with the following CORS-related headers:

2. The server "http://b.com" responds with the following CORS-related headers.


In this case, the server responds with an Access-Control-Allow-Origin: * , which means that the resource can be accessed from any domain in a cross-site manner.
  • Preflighted Request: Unlike "simple rquests" (discussed above), "preflighted requests" send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send.
The only allowed HTTP methods are: PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH.
The only allowed values for the 'Content-Type' header other than the below values are:
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain
The following is an example of a request that will be preflighted.



Let's take a look at the full exchange between client and server. The first exchange is the preflight request/response:

1. Preflighted Request:

2. Response to the preflighted request

3. Main Request: Once the preflight request is complete, the real request is sent:

4. Response to the main request:

  • Java implementation of CORS Filter:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        System.out.println("CORSFilter HTTP Request: " + request.getMethod());
        // Authorize (allow) all domains to consume the content
        ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Origin", "*");
        ((HttpServletResponse) servletResponse).addHeader("Access-Control-Allow-Methods","GET, OPTIONS, HEAD, PUT, POST");
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        // For HTTP OPTIONS verb/method reply with ACCEPTED status code -- per CORS handshake
        if (request.getMethod().equals("OPTIONS")) {
            resp.setStatus(HttpServletResponse.SC_ACCEPTED);
            return;
        }
        // pass the request along the filter chain
        chain.doFilter(request, servletResponse);
    }
Register this filter in web.xml:
<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.ksegvikas.examples.cors.CORSSampleFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Conclusion

CORS (Cross-Origin Resource Sharing) is the standard way of sharing resources from one origin to another. As SOP (Same-Origin Policy) is for security purpose, which restricts sharing of resources from origin to another, CORS provides us with a standard way to access it with proper implementation, as shown in the above examples.