Skip to content

Conversation

@bajtos
Copy link
Member

@bajtos bajtos commented Sep 14, 2016

Following the discussion in #293, I would like to revisit the way how CORS is configured in LoopBack applications.

There are two types of applications that are commonly built using LoopBack, and each type has different requirements when it comes to CORS.

  1. Public facing API servers serving a variety of clients. CORS should be enabled to allow 3rd party sites to access the API server living on a different domain than the client(s).
  2. API+SPA sites where both the API server and the SPA client live on the same domain and the API should be locked down to serve only its own browser clients, i.e. CORS must be disabled.

So far, we were enabling CORS by default to make it easy to build public facing API servers. Unfortunately, this was also making API+SPA sites powered by strong-remoting unsecure by default. What's even worse, this insecure setting was not immediately obvious.

In this pull request, I am removing CORS from strong-remoting, to push the responsibility of enabling/configuring CORS back to the application developer.

Note that this change does not affect LoopBack applications scaffolded by a recent version of slc loopback or apic loopback, as these applications don't rely on the built-in CORS middleware - they configure CORS explicitly in server/middleware.json. (See the project template in loopback-workspace, it is disabling the built-in CORS middleware here and explicitly configuring CORS for the entire server here.

@richardpringle @STRML please review
cc @gunjpan @deepakrkris @raymondfeng @ritch

.end(function(err, res) {
assert(res.get('Access-Control-Allow-Origin') === undefined);
assert(res.get('Access-Control-Allow-Credentials') === undefined);
.expect(200, function(err, res) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you make a cross origin request, you wouldn't get a 200 would you?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

200 may not be the right http status code, test should check for the appropriate error code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my understanding of CORS, it's the responsibility of the browser (the client) to enforce cross-origin policies. The server is required to describe which origins are allowed to access it from the browser.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS (emphasis is mine)

The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on user data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Servers can also notify clients whether "credentials" (including Cookies and HTTP Authentication data) should be sent with requests.

In our tests here, we are not acting like a browser (the supertest library is an HTTP agent only, not a browser-like client) and therefore the status code 200 is expected.

@richardpringle
Copy link
Contributor

Was the affect on API Connect taken into consideration? I know that CORS support is configured at the gateway level there, just something to consider if it hasn't been already.

@bajtos
Copy link
Member Author

bajtos commented Sep 19, 2016

Thank you @richardpringle and @deepakrkris for the review.

Was the affect on API Connect taken into consideration? I know that CORS support is configured at the gateway level there, just something to consider if it hasn't been already.

Yes. There are two parts to the integration with API Connect.

As I explained in the pull request description, applications scaffolded by our generator (apic loopback) setup their own CORS middleware for the entire server. As a result, they are not affected by this change.

When the LoopBack app is run behind APIC gateway, the gateway will provide CORS headers as specified in Gateway's config. As a result, any application-provided CORS headers should be ignored.

I was pondering the idea of disabling CORS in the LoopBack application that are expected to run in APIC environment, but @raymondfeng mentioned good reasons why we should keep CORS in the LoopBack app too:

  1. APIC or other tools might serve API explorer that talks to LoopBack app directly.
  2. Internal web apps might interact with LoopBack app without going through the gateway.

@bajtos
Copy link
Member Author

bajtos commented Sep 19, 2016

Review required
At least one approved review is required.

I have enabled GitHub checks to require each pull request to get an approval before it can be merged. @richardpringle @deepakrkris when the code LGTY, please use the new pull request UI (docs) for approving the patch.

Push the responsibility of enabling/configuring CORS back to the
application developer.
@bajtos
Copy link
Member Author

bajtos commented Sep 19, 2016

The build is failing on windows-0.12 because of a problem on the CI, I am going to ignore the failure and land the pull request.

@bajtos bajtos merged commit 6c89512 into master Sep 19, 2016
@bajtos bajtos deleted the feature/drop-cors branch September 19, 2016 13:22
@bajtos bajtos removed the #review label Sep 19, 2016
@deepakrkris
Copy link
Contributor

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants