Web Applications – HTTPS Site Performing AJAX Calls to HTTP Desktop Application

ajaxdesktop applicationhttpsweb-applications

I'm working on web app that communicates with a locally installed desktop application to get certificate information from the user machine and perform digital signatures.

Currently it's possible to auto generate keys and perform digital signatures with these auto generated keys in javascript using window.crypto. However there is no way to through javascript or html to access the user keys issued by a vendor CA installed on OS or Firefox keystore to perform digital signatures, this is why we relay on installed native application.

This native application is a porting of an old java applet because – hopefully – soon this technology will be not supported for all major browsers (currently it's not already supported in Chrome since September 2015, and also is not supported in Edge), besides the java plugin itself it'll be deprecated in Java 9. Currently we've a Java Web Start working but it's a requeriment to have an alternative way to perform the signatures, since JNLP is not very user frendly way to do so: it requires to download each time a JNLP on a user machine with the signature configuration, there is no communication from browser to JNLP and it's necessary to perform AJAX polling to the backend to check if the signature is finished…

The native application is basically a local http server which exposes the business methods through a REST API, this way it's easy to use from our web app with simply making some AJAX calls an dealing with the result.

It works flawlessly when the web app is deployed in HTTP, the problem is that our web app is secured under HTTPS, but our native application is an HTTP server, so evidently for security reasons by default the major browsers block our AJAX calls from the web app to our native application due to mixed content.

Any CA vendors will issue a server certificate for a localhost domain, and furthermore since the native application is installed on client, the private key will be available on every client machine, so for sure a certificate issued by a official CA it's not a possibility. Also note that our native application must work on a heterogeneous environments: different OS, different browser, different networks so a proxy solution for the SSL is also not an option.

A possible solution which come to my mind is to generate a self-signing certificate and configure our native application to work as an HTTPS server. However I see a flaw in this solution: the native application automatically or the client manually must install this certificate in the client SO trust store or in the firefox trust store, this is a security concern because you're adding a self-signed certificate in a trust store.

My question are:

  • Installing a self-signed server certificate for localhost directly in the trust store it's a security concern, but how is it really dangerous/exploitable? If you issue the cert for CN=127.0.0.1 if there is no proxy on the network or hosts edited it's not possible to a third party server serves content for you there, isn't? Is this solution as bad as it sounds?

  • There is an alternative way to communicate between web app in HTTPS with a native application in a easy manner, user-friendly way and supported for all major browsers?

Best Answer

THE ORIGINAL SOLUTION IS NOT VALID ANYMORE!

Updated Solution

Everyone doing this (github, spotify, blizzard, dropbox, etc) have all seen their certificate revoked last year because the private key was stored locally and considered compromised.

There are 2 workarounds:

  1. create, locally, an ssl certificate binded to localhost/127.0.0.1 and install it in the OS trusted keystore.
  2. In the Secure Contexts Spec, localhost/127.0.0.1 is now considered a potentially trustworthy origin. This means that an HTTPS page calling 127.0.0.1 over http is NOT blocked by Mixed Content. Tested in Edge, Chrome and Firefox. Unfortunatly, Microsoft team has not backported this fix to IE.

If origin’s host component matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy".

Original Solution

You get a standard certificate from a CA for a domain like local.myapp.com and you associate this host with 127.0.0.1 in your dns.

This will enable https calls from your web page to your installed app.

Please note that there may be security issues with this. In fact Chromium intend to block these calls to localhost (or add an option to opt-in --> https://bugs.chromium.org/p/chromium/issues/detail?id=378566). But multiple sites are doing this:

  • Spotify (web player - desktop app) : *.spotilocal.com
  • Github (open file in Github for Mac) : ghconduit.com
  • Dropbox : www.dropboxlocalhost.com

Explanation of how Spotify does it: http://cgbystrom.com/articles/deconstructing-spotifys-builtin-http-server/

With the requirement to use HTTPS, a valid SSL certificate is needed to avoid browsers complaining. Spotify has worked around this problem by registering a domain (*.spotilocal.com) that merely points to 127.0.0.1. But rather than connecting to the top domain, they use a wildcard domain and connect to a random subdomain each time (for example abcrjdknsa.spotilocal.com). The reason for this is to avoid the browser’s max connection limit per domain, enabling more tabs in the browser to concurrently use their API at the cost of an extra DNS lookup.

Related Topic