4

After reading the following, I'm still stuck on making the barest-minimum https://localhost stand-alone install-free webserver java app. It needs to be library-free, use Java 8, and accept connections from the browser without first installing any special client certs. I'm unclear if this is at all possible with self-signed certs because it only has to work for "localhost".

So far I've generated some key files using

openssl genrsa -aes128 -out privkey.pem 2048  # makes privkey.pem
openssl req -new -x509 -key privkey.pem # makes cert.crt

and I've cobbled together the bare minimum Kotlin setup function

private fun ssl():SSLServerSocketFactory {
    val password = "MYPASSWORD".toCharArray()
    val kmf = KeyManagerFactory.getInstance("SunX509")
    val tmf = TrustManagerFactory.getInstance("SunX509")
    val sslContext = SSLContext.getInstance("TLS")

    // initialise the keystore
    KeyStore.getInstance("JKS").let { ks->
        FileInputStream("lig.keystore").use {
            ks.load(it, password)
        }
        kmf.init(ks, password)
        tmf.init(ks)
    }

    // setup the HTTPS context and parameters
    sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null)
    return sslContext.serverSocketFactory
}
ssl().createServerSocket().use { serverSocket ->
            serverSocket.reuseAddress = true
            serverSocket.bind(InetSocketAddress(port))
            logger.info { "WebServer ready and listening on ${serverSocket.localPort}" }

But I'm having trouble how to finish it off: Do I need to make a lig.keystore file? Can this even be done without installing certs on the client's browser?

Benjamin H
  • 5,164
  • 6
  • 34
  • 42
  • 1
    You will need to import your keystore into your jvm runtime. A self signed certificate will just give you a warning in the browser that you will have to trust that signed cert yourself. I have seen this be a massive issue in enterprise environments with companies having security policies which prevent this. – Derrops Dec 12 '17 at 23:33
  • Why? What is the point of HTTPS to the localhost? – user207421 Dec 12 '17 at 23:36
  • @ejp I would like to load a HTML file from a SSL-protected web server that (optionally) includes a javascript file served locally. When I attempted to serve the js file from a non-SSL http://localhost/thefile.js the browser correctly blocked it. – Benjamin H Dec 13 '17 at 00:04
  • @Snickers3192 drat! I was afraid of that. I was hoping that "localhost" got a pass with the error, but if not... bummer. – Benjamin H Dec 13 '17 at 00:05
  • Like @EJP says there isn't any point of ssl within localhost, but I've seen it for testing purposes because of policies or politics. Pretty much to get around it you just put a proxy in front which goes Browser->HTTP->Proxy->HTTPS->Server, if you need to. – Derrops Dec 13 '17 at 00:11
  • @Snickers3192 - .... except that you 1) need to use a real IP for the proxy and 2) provide it with a real cert, and 3) bind, open ports, etc to allow the proxy to talk to the "minimal" server. – Stephen C Dec 13 '17 at 01:52

2 Answers2

5

There are two common approaches to getting a secure connection between a client (browser) and server via HTTPS:

  1. You can obtain SSL certificate for the server that is signed by a Root Certification Authority (CA) that is trusted by the user's web browser by default.

  2. You can generate a self-signed SSL certificate, and have the user import it into their web browser as a trusted cert.

What you have done so far seems to be to generate a server-side keystore with a self-signed cert in it and (more or less) configured the Kotlin server to use it. The problem is the client (browser). There is no safe way to get the browser to trust the self-signed cert without the involvement of the user or the user's sysadmin. (Safe ... as in safe for the user!)

And no legitimate CA should ever issue an SSL cert for "localhost"; e.g. https://www.ssl2buy.com/wiki/how-to-get-ssl-certificate-for-web-applications-that-runs-on-localhost

Impasse.

OK, so lets step back. The purpose of using HTTPS / SSL is to ensure that:

  1. The user's web browser is talking to the correct server, and not some other server that is impersonating it.

  2. The connection between the browser and the server is encrypted so that no third party can snoop on the traffic.

But you are trying to do this for a localhost connection. The localhost IP address is a loopback address. Unless the OS kernel is compromised, you are guaranteed that network packets sent via a loopback connection will not leave the host.

  1. You can dismiss the "impersonation" problem. Assuming that the user's machine has not been compromised, nobody else can launch a "fake" server on the user's machine.

  2. You can dismiss the "snooping" problem. Assuming that the user's machine has not been compromised:

    • The packets won't go off-host, so they can't be snooped on any "external" networks.
    • The only person who can "snoop" the packets on the loopback network is the user him / herself.

So, the solution is simple. Use "http" for your "localhost" connection. It should be secure ... assuming that the user's machine has not been compromised.

Note: if the user's machine has been compromised, then the bad guys have other ways to intercept the traffic that SSL won't protect against.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • First of all +1 for the explination .Follow up question if i created a secure cookie while using my local host, would this be sent to the localhost if it is running HTTP and not HTTPS? If so then secure cookies can be configured to be sent to non HTTPS connections which shouldn't be the case; If not then the localhost is not secure as you pointed out in your answer.. Please explain – JpersaudCodezit Feb 14 '19 at 01:14
  • 1
    There is no good solution to that ... apart from not setting `secure` on cookies if your app is designed to talk to localhost. See https://softwareengineering.stackexchange.com/questions/310720/make-browser-allow-secure-cookie-over-http – Stephen C Feb 14 '19 at 06:10
  • 1
    Actually, my answer didn't say localhost is not secure. What I said / implied was that if someone (i.e. a hacker) was able to intercept traffic on the loopback device, then that is probably the least of your worries. (And they could probably intercept the traffic if you were using https. On any interface!) – Stephen C Feb 14 '19 at 06:14
  • 1
    Finally, if you feel you need to use https for 127.0.0.1, your only real option is a self-signed cert. You could set up your own private CA and issue a cert for 127.0.0.1, but that is potentially dangerous. The cert + private key would work on any host that trusts your private CA. Someone in your organization with access to a machine where the cert + key are installed could co-opt it for evil purposes. – Stephen C Feb 14 '19 at 06:22
0

Another specific case:

I'm facing a web app from https that would load local data at http://localhost

Safari web browser blocks because of unsecure communication (http) in a secure flow (https).

This behavour could be discussed, but in that case self signed certificate for localhost would help., even with a warning from Safari browser.