30

Without divulging TOO much information, I need to setup a web server system that is intended to be used by end users all over the internet.

the use case is such that:

  • end users are (usually) in their homes behind their local firewalls when connecting to the system.
  • The system consists of a remote server hosted by us, strictly over https (using SSL)
  • The authorization mechanism requires user account self-creation on the remote server which, upon successful account creation, will then require a piece of software to be downloaded and installed to the end users' computer. This software contains, among other things, a local webserver.
  • This "local" webserver must also only allow https connections to the user's browser.

Since the distributed software will be a unique web server on every individual users' machine, I'm unsure how or even if it is possible, to get a THIRD PARTY SIGNED SSL certificate that won't cause trustworthiness errors when the user connects to it via the web browser. Of course it can use self-signed SSL certs but the idea is to avoid the browser warnings so that the end users will implicitly "trust" data coming from their own application running its webserver over SSL.

Is this possible?

jww
  • 97,681
  • 90
  • 411
  • 885
Rimer
  • 2,054
  • 6
  • 28
  • 43
  • 4
    Out of interest, why does the connection to the local server, listening only on `127.0.0.1`, need to be over SSL? Who's the man in the middle going to be? – Neil May 07 '12 at 21:31
  • @Neil Alice decides that Bob's webserver receives valuable information and so kills the web server process and inserts her own to take its place. Now Alice gets username/password etc. – chacham15 Nov 01 '12 at 06:51
  • 3
    @chacham15 Where did Alice get the root password to kill the web server process from? And why bother killing the web server process when she can just install a key logger? – Neil Nov 01 '12 at 21:01
  • @Neil The question is a bit confusing, so I created my own pretend scenario: I envisioned the scenario as the designer of the software being paranoid of other running applications on the machine. In order to prevent another application from parading as his application to the end user he wants SSL certificate validation. Now, his application has the webserver as well as other things which may get information from other places/control other things and he doesnt want the user to be duped with a fake UI which does other things like collect the information and re-transmit it elsewhere. – chacham15 Nov 01 '12 at 23:28
  • 4
    @Neil if the remote website tries to access the local website then you will be blocked if serving mixed content is blocked. – Joel McBeth Apr 08 '15 at 16:09
  • 1
    Also, note that localhost will share cookies, localstorage, etc among all applications - even on different ports. For this use case what you really want to do is have localhost.yourthingmabob.com and set the DNS cache time to years instead of minutes, days, or hours. – coolaj86 Jun 16 '15 at 02:47
  • If you are already installing software on other people’s computers, then why not just also install cert in the trusted root repository? – Synetech Jun 04 '16 at 00:49
  • (Also, this system could be abused by bad guys. For example, it could be used to sneak bot software on a system and allow the C&C to communicate with the zombie over an encrypted connection.) – Synetech Jun 04 '16 at 00:50

5 Answers5

30

localhost

You will never be issued a proper https cert for localhost. It is strictly forbidden. Because reasons.

In short:

  • Misconfigured devices actually exist, in the wild, that wait for lookups before resolving localhost from /etc/hosts
  • If a router defines localhost.foo.local it may cause localhost to resolve incorrectly (you've probably seen this class of error before)

You can create a root certificate and then create a so-called "self-signed" certificate, signed by the root ca you created. You'll still get the ugly warning screen, but it'll work.

2023 Update: caddy

The solutions below still apply, but caddy can make them even easier.

It can create root certificates that plug into your OS keychain, and there's a DuckDNS plugin so you could have public certs on a public or private IP via DNS validation, etc.

localhost.YOURSITE.com (points to 127.0.0.1)

In lieu of actual localhost certs, I do what Eugene suggests - create a 127.0.0.1 record on a public domain.

You can get free HTTPS certificates for localhost.YOURSITE.com via Let's Encrypt via https://greenlock.domains. Just choose the DNS option instead of the HTTP File Upload option

Point your localhost.MY-SLD.MY-TLD to 127.0.0.1

  • Purchase a *.localhost.example.com cert and issue each installation a secret xyz.localhost.example.com (and include it in the public suffix list to prevent attacks on example.com)
  • Use a greenlock-enabled app to generate such certificates on the fly (through https://letsencrypt.org) directly on the client (or pass them to the client)

If you do not get included in the PSL note that:

  • sessions, localstorage, indexeddb, etc are shared by domain
  • changing the port does not change their sharedness

Be Your Own Root Certificate

Update: with things like greenlock that use ACME / Let's Encrypt, this is no longer particularly relevant.

This is probably a really bad idea because we don't want users becoming accustomed to installing Root CAs willy nilly (and we know how that turned out for Lenovo), but for corporate / cloned machines it may be a reasonable low-budget option.

coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • Awesome! It will help me test the feasability of my project before registering my own certificate, thanks a bunch! – Aurelien Ribon Jun 12 '15 at 09:23
  • 1
    Just remember that localhost.daplie.com will have shared cookies, localStorage, indexeddb, etc, among everyone who uses it, so you will eventually want to get your own. – coolaj86 Jun 16 '15 at 02:50
  • I am slightly concerned about a malicious party having the capability to revoke certificates by knowing the private key, see: https://letsencrypt.github.io/acme-spec/#proof-of-possession-of-a-prior-key I'm not sure if "prior key" refers to the account private key or the certificate's private key (which for localhost.daplie.com is publically available) – joonas.fi Feb 02 '17 at 10:19
  • @joonas.fi You should be much more concerned about a malicious party DNS spoofing and directing your 'localhost' traffic to somewhere that isn't. This isn't a production solution (see the links about why it's forbidden). Also, Greenlock (ACME / Let's Encrypt) now supports dns-01 challenges so you can get your own certificate without private keys exposed willy-nilly. – coolaj86 Feb 03 '17 at 15:24
  • @CoolAJ86 MITM is a possibility with DNS query response spoofing yes, though that can be mitigated with DNSSEC. But a MITM attack only would affect one targeted victim, whereas a malicious party revoking the certificate of localhost.daplie.me would be able to take down potentially hundreds of applications and all their end users, if managed to be revoked by the "prior key" mechanism. – joonas.fi Feb 04 '17 at 14:54
  • The localhost.daplie.me certs didn't work for in June 2017 (macos, chrome) – loevborg Jun 27 '17 at 10:48
15

I had this same requirement. So the reason why you have to use SSL is because just about every browser now barfs if you use https and try to connect to an http resource even if the http resource is on localhost which is silly to me.

Because of JS SOP our localhost web server serves up a js file and then the JS inside the webapp can make calls to this localhost webserver.

So we made local.example.com point to 127.0.0.1 and actually bought an SSL certificate for this hostname. We then ship the private key inside this web server which gets installed on the user's computer. Yes, we're crazy.

All of this actually works quite well. We're been running like this with a few hundred users for about 6 months now.

The only problem we sometimes run into is that this doesn't work right when a user is using a proxy server. The requests are sent to the proxy server and it tries to connect to 127.0.0.1 at the proxy server which obviously doesn't work. The work-around is to add an exclusion to the proxy server config so that it bypasses the proxy server for requests to local.example.com

Another scenario where it will get a little tricky is when users try to use Citrix or Terminal Services. You have to make sure the web server for each user is running on a different port and then inform your remote web server of the port number so that pages generated on the server will have the right port number. Fortunately we haven't run into this yet. It also seems like more people are using virtual machines these days instead of Citrix.

Did you ever find a better way?

Sarel Botha
  • 12,419
  • 7
  • 54
  • 59
  • 2
    This is an excellent idea (DNS record pointing to 127.0.0.1). Although it's a bit hackish to bundle your key/cert with the app, I think this is pretty much the only way to go. How do you deal with expiration? Have the app download a new cert? – andrew Mar 21 '14 at 05:35
  • I agree, it seems crazy to bundle the private key with the app. Just don't use this certificate on a real server somewhere else and it's fine. Our application is a SAAS application so we're always releasing updates for it. The application uses Java Web Start so it automatically updates. You can also get an SSL certificate for $5 per year these days so just get one for 5 years and you won't have to worry about it for a while. – Sarel Botha Mar 21 '14 at 19:37
  • 1
    I have exactly the same problem. I'm wondering if there is any security implication of making the private key for this certificate essentially public. – yegodz Apr 23 '15 at 17:30
  • Also, where do you get SSL certs for $5/year? – yegodz Apr 23 '15 at 17:31
  • Thank you for your experience! But do you understand, that you have Man-in-the-Middle attack risk? An attacker can spoof your domain, if he gets your private key. We are going to make similar local server, but we are going to generate own Root CA and SSL certificate for "127.0.0.1" domain. At the first execution the local server installs Root CA certificate to Windows Certificate Storage. But it doesn't work good for Firefox, because Firefox uses own certificate storage. – dizel3d Nov 16 '15 at 12:05
  • 1
    Note that this will certainly lead to the revocation of your certificate by the authority. Embedding the private keys in a software is considered a breach of the certificate usage. Well-known companies have had their certificates revoked for this very reason: see e.g. [Ciso case](https://groups.google.com/forum/#!msg/mozilla.dev.security.policy/T6emeoE-lCU/-k-A2dEdAQAJ), [Blizzard case](https://groups.google.com/forum/#!msg/mozilla.dev.security.policy/pk039T_wPrI/tGnFDFTnCQAJ), and there have been reports for Spotify, GitHub, Dropbox, as well, and probably more... So do this at your own risk. – dim Mar 28 '18 at 10:44
2

Probably you can make us of this offering by GlobalSign (other CAs offer comparable services). In brief, the offering lets you have a CA certificate (and enroll end-user certificates for localhost / whatever ) which will be signed by GlobalSign certificate. The cost can be significant though (I believe they determine it on case by case basis).

Eugene Mayevski 'Callback
  • 45,135
  • 8
  • 71
  • 121
  • Does this mean I must create my own CA in order for this to work? – Rimer Jul 22 '11 at 16:52
  • @Rimer In order to avoid a browser warning on client side, you need to build a trusted certificate chain, i.e. the certificate used in deployed web server (the one that will run on the client side) must be signed using the CA certificate which *in turn* must be either trusted by the browser or be signed by a trusted CA. This is what GlobalSign and other known CAs offer. Now you don't need to create a CA - if you have built such a complex application, adding certificate generation to your server requires 15 minutes of coding. – Eugene Mayevski 'Callback Jul 22 '11 at 17:11
  • I guess my question is then, is it possible to get a trusted CA to SIGN a certificate for a server that will be accessed at "https://127.0.0.1/" or "http://localhost/" ? – Rimer Jul 22 '11 at 18:14
  • @Rimer I guess no, you must become a trusted CA yourself (i.e. get a special certificate from a known CA as discussed above), and then issue such certificates and perform certificate revocation management. – Eugene Mayevski 'Callback Jul 22 '11 at 18:42
  • 2
    @Rimer think about this interesting conundrum: say you do get a trusted CA to sign your cert for localhost. What happens if an attacker would then take his signed cert to the victims computer? – chacham15 Nov 01 '12 at 06:46
1

Since you're on localhost, you can tell your browser to trust any certificate you want.

Make a self-signed certificate for localhost, and tell your browser to trust it.

  • Can you do that using another program's logic, in example, through a Java application? It would be a pain to have to do that by hand on every machine that needs access to a server with such certificate. If the application itself can make the OS or (any) web browser trust that certificate, that would probably be ok, right? – David Apr 07 '17 at 01:07
0

The solution "Point your localhost.MY-SLD.MY-TLD to 127.0.0.1" provided by provided by CoolAJ86 works fine, and you see a more detailed explanation here:
How PLEX is doing https for all its users

PS: I just don't know how sustainable this is, because someone with a similar scenario had their key revoked by the CA as if the key had been compromised.

drizin
  • 1,737
  • 1
  • 18
  • 44
  • https://telebit.cloud uses Greenlock and Let's Encrypt to issue certificates on the device so that they aren't revoked. – coolaj86 Nov 30 '18 at 02:51