Vladimir Dyuzhev, author of MockMotor

Vladimir Dyuzhev
MockMotor Creator

CORS Support


CORS is automatically supported by MockMotor since MockMotor 1.8.2012. You don't have to do anything.

CORS in Mocks

Without a further ado, since version 1.8.2012 you do not need to do anything to enable CORS for any mock service. Every service by default already supports CORS and responds accordingly.

Navigate to the service page and set the Generate CORS Headers to Auto:

Want a Finer Control?

For any response you can provide your own values for CORS headers. MockMotor uses your values if it finds them.

Missing CORS response headers are still auto-generated. For example, here Access-Control-Allow-Origin is provided by MockMotor, while two other headers have custom values:

What is CORS

The explanation below is simplified. For detailed documentation read Mozilla MDN article.

CORS stands for Cross-Origin Resource Sharing. The name doesn’t make it any clearer what it’s actually for.

Let’s figure it out.

What Problem it Solves

CORS addresses a very common problem in the web. A typical page loads its resources (content, images, scripts, data, text and graphical ads) from a number of sites. Some of those sites can be compromized. These sites then inject spying scripts into the page and these scripts will try and steal data from the other sites under the user id.

For example, a web forum can contain an infected script posted by a user. I visit the forum, my browser downloads and executes the script, and that script then sends requests to a banking site I have visited shortly before. Without a protection mechanism in place the browser amends the script requests with the bank’s cookie permitting the malicious script to pretend it is me and steal.

Same Origin Policy

That risk was countered in 1995 with the Same Origin Policy.

The Same Origin Policy states that a page or script can only access the resources loaded from the same site.

“Same site” generally means “same protocol, host and port”.

For example, for a page or script loaded from URL http://example.com:1234/hello, these URLs will or will not be considered Same Origin (i.e. safe):

URL Same Origin or Not
http://example.com:1234/balance Yes - same protocol, host and port
https://example.com No - HTTPS instead of HTTP
http://example.com:8080 No - different port
http://secure.example.com:1234 No - different host
http://site.com:1234 No - different host

The Same Origin rules are not a strict specification and differ even between browsers. For example, for IE only “same protocol and host” are considered.

For the attack described above the failure to pass the Same Origin check means that the cookie obtained by me on the banking site is not available to the infected script. The request is unauthenticated and so fails.

However, note that the script is still able to perform the request to the banking site. The request itself is not blocked by the Same Origin policy, that came later with CORS.

Cross-Origin Resource Sharing

Here I mostly talk about XMLHttpRequest as it is the primary candidate for mocking.

As the web was becoming more complex and interlinked, more and more sites began actually require cross-site calls. Some web sites were a mashup of data loaded from various data sources and their scripts needed to work with all these sources.

Web was in need of a more flexible (but still secure) way to control access.

The solution was to let the servers (sites) decide who can call them and how.

With CORS, a browser still remembers the origin for all of its loaded resources. However, it doesn’t automatically deny a script an access to another site. Instead, it consults with the target site during or before the script request.

Simple Requests (GET, POST, HEAD)

The script can request to perform a HTTP GET, POST or HEAD call to a not-same-origin server. These HTTP methods are considered simple because they can be performed by other means, too. For example, inserting an <img> tag with a src attribute into DOM will perform a GET.

For these simple cases the browser executes the request immediately. However, it adds a few special HTTP headers to the request. If the response doesn’t contain the expected matching response headers, the response is hidden from the script.

Note that just like with the Same Origin Policy, the request is not blocked. However, its results are not provided to the script if it is not explicitly permitted by the server.

Non-Simple Requests: Pre-Flight with OPTIONS

For other HTTP operations (PUT, DELETE, etc) and for some other more corner cases, the browser performs a pre-flight check first.

The browser sends a HTTP OPTIONS request to the site the script wants to access. It adds HTTP headers that provide the site with the information about the upcoming call.

If the server doesn’t respond in a way that permits the request, the actual call never happens.

CORS Response

If the site was created without CORS in mind, it will either omit the required CORS headers or even reject the OPTIONS request. The browser then will not allow the script to access the data or to perform the call. This is very good, as the older sites are protected by default.

If the site supports CORS, the HTTP 200 in the response is not enough to permit the call. The server must confirm each CORS header with a matching reply header. Any mismatch and the browser, again, will block the data or the call. This is done to ensure that the site owners have put some thought into the security and would not just reply with HTTP 200 to every CORS call.

The Server is in Control

With CORS, the server can apply a fine-grained control to who can call the server and how. Because the server team knows the best what are the valid uses of their service, they are in the best position to apply the rules that allow for a flexible legitimate use, but stop the attack attempts.

The rules can vary from very strict to very lax.

The mentioned above bank would only allow calls from the same origin, i.e. only from scripts loaded from the bank own site.

A web widget could allow access to client sites but no one else.

A public weather service could allow reading the data to anyone interested.

The main thing is that the access control decision have to be made explicitly. If the site simply ignore CORS, the default access from the browser point of view is DENY.

Examples of CORS Client-Server Exchanges

Simple POST Request

A POST is considered a simple request, and even for cross-domain calls the browser executes it as is. It however adds CORS headers Origin and Access-Control-Request-*:

POST http://127.0.0.1:7080/SelfTest/CORSCFG HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/json
Access-Control-Request-Headers: Content-Type, X-Foo
Origin: http://foobar.com/
Access-Control-Request-Method: POST, PUT
Content-Length: 14
Host: 127.0.0.1:7080

{"Hello":true}

If the server permits the call from that origin, it provides the response and the matching response Access-Control-Allow-* CORS headers:

HTTP/1.1 200 OK
Date: Tue, 30 Oct 2018 02:55:22 GMT
Content-Type: application/json; charset=UTF-8
Access-Control-Allow-Headers: Content-Type, X-Foo
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT
Transfer-Encoding: chunked

{
  "status":"OK"
}

Pre-Flight OPTIONS Request

Before executing a cross-domain request with HTTP method other than GET, POST or HEAD, browser sends an OPTIONS request.

The request has the Origin header (marking the origin of the script/source that executes the request) and Access-Control-Request-* headers:

OPTIONS http://127.0.0.1:7080/SelfTest/CORSCFG HTTP/1.1
Accept-Encoding: gzip,deflate
Access-Control-Request-Headers: Content-Type, X-Foo
Origin: http://foobar.com/
Access-Control-Request-Method: PUT, POST, DELETE, OPTIONS, GET
Host: 127.0.0.1:7080

If the server is OK with such a request, it provides the matching response Access-Control-Allow-* CORS headers:

HTTP/1.1 204 No Content
Date: Tue, 30 Oct 2018 02:51:14 GMT
Content-Type: text/xml; charset=UTF-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: PUT, POST, DELETE, OPTIONS, GET
Access-Control-Allow-Headers: Content-Type, X-Foo

The browser then executes the actual request (still adding CORS headers to it, too!):

PUT http://127.0.0.1:7080/SelfTest/CORSCFG HTTP/1.1
Accept-Encoding: gzip,deflate
Access-Control-Request-Headers: Content-Type, X-Foo
Origin: http://foobar.com/
Access-Control-Request-Method: PUT, POST, DELETE, OPTIONS, GET
Host: 127.0.0.1:7080
Content-Length: 14

{
  "feedback":"Accepted"
}