How to manage SSL key for self host HTTPS - ssl

I have Windows service that listens for https requests on an end user's machine, is there an accepted way of creating or distributing the private key in this circumstance? Should I be packaging a real key specifically made for localhost requests (e.g. local.mydomain.com) or generating a self signed key and adding a trusted root CA at install time?
If it matters, the service uses Nancy Self Host for handing the requests and it runs on the SYSTEM user. We have a web app running over https that will be making CORS requests to the service, the user will be using it on a standard web browser (>=IE10). Only the machine onto which the service is installed will be making requests to it.
Thanks.

I have 2 options for you, doing the right way and not doing it at all.
The right way
(Warning: it costs a plenty)
Let's say your application is hosted in the cloud, under kosunen.fi. Main portion is served from the cloud at https://www.kosunen.fi.
Buy DNS delegation for this domain. Resolve localhost-a7b3ff.kosunen.fi to either 127.0.0.1 / ::1 or the actual client's local ip address 10.0.0.63 / fe80::xxxx
Buy subCA or get mass certificate purchase agreement, issue certificates (earlier) or get certificates issued (latter) on demand for each localhost-a7b3ff.kosunen.fi. These certificate will emanate from a trusted global CA and therefore are trusted by all browsers. Each certificate is only used by one PC.
Set up CORS/XSRF/etc bits for *.kosunen.fi.
Done.
Not doing it
Realise that localhost traffic, is, in practice quite secure. Browsers typically refuse http://localhost and http://127.0.0.1 URLs (to prevent JS loaded from internet probing your local servers).
You'll still need at least one DNS entry, localhost.kosunen.fi that resolves to 127.0.0.1 / ::1, browsers will happily accept http://localhost.kosunen.fi even though host name resolves to 127.0.0.1.
What are the risks?
Someone running wireshark on client machine -- if someone has privileges, your model is done for anyway.
Someone hijacks or poisons DNS -- sets it up so that www.kosunen.fi resolves to correct ip, but localhost.kosunen.fi resolves to their internet ip. They steal requests user's browser makes and can include JS.
Mitigate that ad hoc -- only serve data from localhost, not scripts. Set up restrictive CORS/XSRF/CSRF.
You are still left with CORS for HTTP x HTTPS there are solutions to that.
Super-simple CORS
Here between 2 ports, 4040 and 5050, that's just as distinct as between different hosts (localhost vs your.com) or protocols (HTTPS vs HTTP). This is the cloud server:
import bottle
#bottle.route("/")
def foo():
return """
<html><head></head>
<body><p id="42">Foobar</p>
<script>
fetch("http://localhost:5050/").then(
function(response) {
console.log("status " + response.status);
response.json().then(
function(data) {
console.log(data);
}
);
}
);
</script>
</body></html>""".strip()
bottle.run(host="localhost", port=4040, debug=True)
And this is localhost server:
import bottle
#bottle.route("/")
def foo():
bottle.response.headers["Access-Control-Allow-Origin"] = "*" # usafe!
bottle.response.headers["Access-Control-Allow-Methods"] = "HEAD, GET, POST, PUT, OPTIONS"
bottle.response.headers["Access-Control-Allow-Headers"] = "Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token"
return """{"foo": 42}"""
bottle.run(host="localhost", port=5050, debug=True)
Making it safe(r): in the localhost server, read request Origin, validate it, e.g. starswith("https://your.com/") and then return same Allow-Origin as request Origin. IMO that ensures that a compliant browser will only serve your localhost content to JS loaded in your.com context. A broken browser, or, any program running on same machine can, of course, trick your server.

The best way to go about this is to create a self-signed certificate on your local hostname and add an exception to that in IE.
There are a few services that offer 'localhost over SSL', but these all require the private key to be shared by all users using the service, effectively making the key unusable from a security perspective. You might not care about that too much as long as you only allow connections on the local network interface, but CA's try and revoke these certificates as they compromise the integrity of SSL (see for instance http://readme.localtest.me/).
It should be possible to make a mixed-content (HTTPS to HTTP) CORS request on IE11 (see https://social.technet.microsoft.com/Forums/ie/en-US/ffec5b73-c003-4ac3-a0fd-d286d9aee89a/https-to-http-cors-issue-in-ie10?forum=ieitprocurrentver). You just have to make sure that both sites are in a trusted zone and allow mixed-content. I'm not so sure if the web application can / should be trusted to run mixed-content, so the self-signed certificate is more explicit and provides a higher level of trust!
You can probably not use a real certificate signed by a trusted CA since there is no way for a CA to validate your identity based on a hostname that resolves to 127.0.0.1. Unless you create a wildcard certificate on a domain name (i.e. *.mydomain.com) that also has a subdomain local.mydomain.com resolving to your local machine, but this might interfere with existing SSL infrastructure already in place on mydomain.com.
If you already have a certificate on a hostname, it might be possible to set that hostname to 127.0.0.1 in your client's hosts file to work around this, but again this is more trouble and less explicit than just making a self-signed certificate and trusting that.
BTW: Don't rely on the security of the localhost hostname for the self-signed key as discussed here: https://github.com/letsencrypt/boulder/issues/137. The reason behind this is that some DNS resolvers send localhost requests to the network. A misconfigured or compromised router could then be used to intercept the traffic.

Related

HTTPS Connection over LAN

I am new to server management and all that HTTP stuff. I am setting up an internal server for my home to serve websites internally, my website needs to register a service worker and for that, I'll need an SSL Certificate and HTTP connection, which seems impossible in my case as all localhost or internal IPs are served over HTTP with untrusted SSL Certificates.
If anyone could suggest a way around serving websites over HTTPS with trusted certificates so that service worker can be used.
Note: I'll be using Xampp Apache for my Linux server with a static internal IP.
If you need 'trusted cert for any client', I may say "no way".
But if you need 'trusted cert for your client only', you have a way to do that.
I guess you published self-ssl cert for your Apache. In the case, you just install the cert into your client.
example: The following link tell us the case of client = Chrome on Windows.
https://peacocksoftware.com/blog/make-chrome-auto-accept-your-self-signed-certificate
If you use any programming language as a client, you may need another way to install the cert.

Kubernetes/Ingress/TLS - block access with IP Address in URL

A pod is accessible via nginx-ingress and https://FQDN. That works well with the configured public certificates. But if someone uses https://IP_ADDRESS - he will get a certificate error because of the default "Kubernetes Fake Certificate". Is it possible to block access completely using the IP_ADDRESS url?
I think you would first need the TLS handshake to complete, before Nginx could deny the access.
On the other hand, HAproxy may be able to close the connection while checking the ServerName. Say setting some ACL in your https frontend, routing applications to their backends. Though I'm not sure this would be doable unless mounting a custom HAproxy configuration template into your ingress controller.

Allowing websockets over https for local server

I need some direction for projects i made.
I have an existing node-red in local server that send data using websocket to my domain in my hosting. Everything is working fine over http but the problem occured when i used https for my domain. I used websocket ws: before then i changed it wss: to work over https but it still did not work because i realize i need SSL certificate for my local server too. Then, I used self-signed certificate for my local server. It works but i have to manually input my local server DDNS in my browser to allow wss first then back to my hosting domain, i can't expect the users to do this.
I used DDNS on my local server because i have no static IP. I try to call for my ISP for provide static IP but it can't be done in the near future.
Because i have no static IP i can't register domain and i can't use CA Certificate for local server SSL.
My question is:
Is there a way to allow ws to work over https?
If not, is there a way to allow unsafe wss on my domain page over a button or a prompt when user go to my page? so user don't have to manually input my local server DDNS.
Or other way you may suggest.
No, Websocket connections are bootstrapped over HTTP, Secure Websocket connections over HTTPS. The TLS session is setup by the HTTPS connection.
It's not clear what you are asking here. But the only way to get a self signed certificate to work with a websocket connection is to install that certificate into the browsers trusted certificate store before trying to access the site. The browser will not prompt to trust a certificate for a websocket connection.
You can use Letsencrypt with a proper Dynamic DNS setup. This is where you have a fixed domain name and a script on your machine that updates the IP address the domain name points at. The hostname will stay the same so the certificate issued will always have the correct CN/SAN entry. Letsencrypt certificates are signed by a trusted CA certificate that will already be present in your browser.

HTTPS Spoofing in order to support legacy application

I have a legacy application that has a hardcoded url (I don't have access to the source) in which it tries to download a file. The url takes the form:
https://pre.hostname.org/index.json
but the organization that hosts that site has dropped that hostname and is using a new hostname, so that the url should be of the form:
https://hostname2.org/pre/index.json
I don't own the application source code or either website, but it occurred to me that I might be able to do some spoofing if I set up a redirect on my local webserver and point the old hostname to my webserver using the C:\windows\system32\drivers\etc\hosts file.
On my webserver in a lighttpd conf file:
$HTTP["scheme"] == "https" {
$HTTP["host"] =~ ".*" {
url.redirect = ( "^/(.*)$" => "https://hostname2.org/pre$0" )
}
}
On the client machine with the legacy application in the hosts file:
0.0.0.0 hostname.org
(0.0.0.0 represents the hostname of my webserver with the redirect instructions)
With this setup I can, on the client machine, access the old url in a web browser, and the redirect happens. However, it does not work from the legacy application, and I think it's due to the SSL certification hostname not matching.
If I use Edge browser, for example, I have to workaround the warning:
The hostname in the website's security certificate differs from the website you are trying to visit.
Error Code:
DLG_FLAGS_SEC_CERT_CN_INVALID
I have administrator access on the client machine, the webserver, etc. I obviously trust my webserver even though it doesn't match the cert...
I totally accept that this is as it should be -- that this is part of the protection that https and SSL certificates provide -- what I'm asking is, is there a way to cause my legacy application to ignore this situation? A way to circumvent https protection for this particular hostname / certificate system-wide, so that it will take effect for whatever API the legacy app is using to download the file through https?
is there a way to cause my legacy application to ignore this situation?
Since you only have the binary of the application you might try to replace the hard-coded domain name in the application with a domain you control, i.e. binary patching. Note that would not work if the application is signed since it would break the signature.
You could also try to create your own CA, import it as trusted into your system and use this CA to create your own certificate for the domain in question. If the application just does the simple certificate verification without any pinning of certificate or CA and with using the systems trust store, then it should accept the certificate you've created yourself because it trusts your CA and should thus accept the redirect.

SSL: where is the certificate hosted? when does the verification occurs?

I am quite confused here:
I use DNSMadeeasy to manage my DNS. I have two apps.
One is Heroku hosted, and has https on https://example.com - Heroku has many great tutorials to setup the certificate, it hasn't been a problem.
The other one is a wordpress, hosted in 1and1 (though it shouldn't matter here), and is reachable at http://subdomain.example.com and we want it to be available at https://subdomain.example.com
1and1 does sell SSL certificate, but their automated setup works only when one uses their services for DNS also, as they say. Their support says it should be DNSMadeEasy which should be hosting our SSL certificate. I have the feeling it is not true, because for https://example.com, DNSMadeEasy was never involved.
Questions:
When does certificate querying occurs? Before, After, or in parallel of DNS resolution?
Who is hosting a certificate? The DNS provider? The server (accessible like a sitemap.xml at the root for instance)? A third party?
To enlarge the case, in general if I have a personal server with a fix IP, how can I communicate through https with a valid certificate?
In my case, how can I get my way out of it to make https://subdomain.example.com work?
You are right for not believing the 1and1 suggestion.
To answer your questions:
When does certificate querying occurs? Before, After, or in parallel
of DNS resolution?
A client resolves domain name to an IP address first. So DNS resolution happens first.
Who is hosting a certificate?
The server (in simplistic terms) hosts the certificate.
When a client wants to connect to your site (via HTTPS) it will first establish a secure connection with that IP address on port 443 (this is why usually (without SNI) you can only have one SSL certificate per IP address). As part of this process (which is called handshake) a client can also specify a server name (so-called server name extension) - this is a domain name of your site. This is useful if you have an SSL certificate that is valid for multiple domains.
A good/detailed explanation how it works can be found here
http://www.moserware.com/2009/06/first-few-milliseconds-of-https.html
if I have a personal server with a fix IP, how can I communicate
through https with a valid certificate?
Your server will need to be able to respond on port 443 and have/host an SSL certificate for a domain that resolves to that IP address.
In my case, how can I get my way out of it to make
https://subdomain.example.com work?
You need to purchase a certificate for subdomain.example.com and install it on the wordpress server.
Usually in hosted solution like yours you have 2 options:
Buy the SSL certificate via the provider (1and1 in your case) - a simpler option, they will configure everything for you.
Buy the SSL certificate yourself. Here you will most likely need to login to your 1and1/Wordpress management interface and generate a CSR (essentially a certificate request). Then you purchase the SSL certificate using this CSR and then you can install it via the same management interface.
The process will look similar to this:
http://wpengine.com/support/add-ssl-site/