Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable support for Cordova and Electron applications #39

Closed
wants to merge 1 commit into from
Closed

Enable support for Cordova and Electron applications #39

wants to merge 1 commit into from

Conversation

mudspot
Copy link
Member

@mudspot mudspot commented Dec 2, 2017

Problem Statement
When a Cordova Mobile application make a Javascript call to HAT endpoints, (with the correct headers, tokens and credentials), a 403 Forbidden status is always returned by HAT.

Detailed Description
The above issue has been reported before
playframework/playframework#5193

The cause is during a call to a webservice, Cordova would set the Origin header to file://. And the CORSFilter in the Play Framework would reject it. This observation is further tested/verified with Postman or curl calls.

Resolution
Play Framework has resolved this issue by introducing the setting play.filters.cors.serveForbiddenOrigins. The default value is false.

This PR adds the above setting and sets the value to true.

Extended Impact
Web literature seems to suggest that Electron applications would encounter the same error.


HAT DCO
Signed-off-by: Terry Lee terry.lee@nogginasia.com

@AndriusA
Copy link
Contributor

AndriusA commented Dec 2, 2017

As the issue you have linked says:

Allowing file:// origins seems like a really bad idea to me.

Are there alternatives? I am not very familiar with Cordova, but if anything, the origin header should not be sent at all.

Have you properly configured your app's domain whitelist? http://cordova.apache.org/docs/en/7.x/guide/appdev/whitelist/index.html

I can also find related issues in cordova itself:
https://issues.apache.org/jira/browse/CB-8434

I can also find lots of discussions mentioning ionic, cordova, phonegap, etc and in no case it is recommended to allow for the file:// origin, so you would need to find a way of configuring your application correctly to instead send a null origin.

@mudspot
Copy link
Member Author

mudspot commented Dec 2, 2017

Hi Andrius,

The whitelisting only controls which the cordova application is allowed to make requests to. It doesn't control/influence the response of the server.

No matter what. A cordova application loaded on the mobile will always send 'Origin: file://' (which the HAT will always reject)
Origin is a forbidden header name which the browser/cordova will refuse to allow an override.
I have tried setting the header['Origin"] myself. The code is always forbidden by cordova, and all desktop browsers.

A quick google search also says that it's impossible to programatically set Origin (due to security concerns. You don't want program to mock where it is from).
https://stackoverflow.com/questions/46808011/how-to-set-the-origin-request-header

I think this is why the play.filters.cors.serveForbiddenOrigins setting was accepted into Play Framework in the first place to allow cordova and electron application to call it.

@mudspot
Copy link
Member Author

mudspot commented Dec 2, 2017

Our own backend is also written in Play Framework. Our cordova application is calling it fine. So I made a close examination of our configuration and noted that in our setup, we have a nginx proxy in front of the Play backend.

The proxy server modifies the Origin setting to keep both parties happy.

Our nginx config

 sendfile on;
 sendfile_max_chunk 1M;
 tcp_nopush on;
 gzip_static on;
 
 set $origin "http://workaround-for-cordova";      <---- SEE THIS
 if ($http_origin ~* "http") {
   set $origin $http_origin;
 }
 proxy_set_header Origin $origin;  <--- ORIGIN changed by nginx proxy.
....```

@AndriusA
Copy link
Contributor

AndriusA commented Dec 2, 2017

yes, and the nginx workaround has exactly the same effect as just allowing file:// - you merely hide the fact from your backend

And indeed in the general case Origin header cannot be set programmatically, which is exactly because it is used as a security measure to prevent a user being tricked into sending or requesting information from a different backend than they think they should be talking to.

Some recommended reading: https://code.google.com/archive/p/browsersec/wikis/Part2.wiki#Same-origin_policy

Perhaps the most important security concept within modern browsers is the idea of the same-origin policy. The principal intent for this mechanism is to make it possible for largely unrestrained scripting and other interactions between pages served as a part of the same site (understood as having a particular DNS host name, or part thereof), whilst almost completely preventing any interference between unrelated sites.
...

Now an app running on the phone (as opposed to a browser) has no reason in setting the Origin header in the first place.

Perhaps your workaround lies within how Cordova opens chrome:
https://vxlabs.com/2016/03/17/fixing-the-cordova-browser-platform-access-control-allow-origin-error/

Ionic themselves have a post on this: http://blog.ionicframework.com/handling-cors-issues-in-ionic/. Specifically:

Your origin will not exist, since you are running off of a file:// URI; therefore, any request outwards will not require a CORS request.

Though I am not clear whether this will mean that the browser will not care to check CORS directives but file:// will be included in Origin or not

@mudspot
Copy link
Member Author

mudspot commented Dec 7, 2017

Concluding Remarks/Solution

Regarding above comment

...Though I am not clear whether this will mean that the browser will not care to check CORS directives but file:// will be included in Origin or not

Indeed the access-control-allow-origin directives in the links in the comment above, are all pertaining to desktop browsers. During development of Cordova applications (or any web app), the app is usually served locally with a http://localhost address. The desktop browser itself will block calls originating from javascript to backend application servers. The above links discuss ways to disable/get around this sandboxing.

The problem statement
As stated, our problem is not with making backend calls from javascript within the browser. We are able to break out of the browser to make calls to any service. However, when we put our Cordova application inside the mobile phone, the header Origin: file:// is automatically attached by the Cordova platform right before the calls to the backend server.

This addition by the Cordova platform's $http causes backend services written in Play Framework to forbid access. And HAT is written in the HAT framework.

Rejected solution
Although the Play Framework can be reconfigured to ignore the Origin header, it's deemed a security concern/flaw.

On the other hand, it's impossible to modify the Origin header sent by Cordova.

So how do we solve this impasse?

Solution
-> Replace the use of Cordova's $http with something else.

We found the replacement with the cordova plugin
https://github.com/silkimen/cordova-plugin-advanced-http

The above plugin does not auto include the Origin: file:// header in its web calls.
The plugin is for cordova applications only.

@AndriusA
Copy link
Contributor

Thank you and happy that there was an easy workaround, closing this for now

@AndriusA AndriusA closed this Dec 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants