Does Node.js honor HPKP/support certificate pinning? - node.js

Does Node.js support certificate pinning? More specifically, if a server passes a HPKP header on the first connection, will Node.js honor that setting?
Note that this is for library in which a client connects to my server. I don't care if the HTTPS server in Node supports certificate pinning.
I also understand that I can inspect the certificate manually and there are a few third party libraries which will check on every connection or monkey patch the request library. I'm not asking about that functionality, either.
My plan is to check the certificate the first time and reject if it doesn't match. However, that doesn't do me any good if the TLS cert is changed after that first call.

Use res.socket.getPeerCertificate().fingerprint property of HTTPS response, compare it with your preshared value.

Related

Squid proxy configuration for client SSL termination

I would like to get the recommendation on how to configure Squid (latest version) with client SSL termination.
The requirement is to provide proxy access to the internet for the client who has no ability to install a custom CA certificate.
Following the documentation here, it is possible to use HTTPS for the browser-proxy connection the same way as HTTP.
However, the only way to achieve that is to use SSL Interception with self-signed CA certificate, which cannot work in my case.
Can someone please advise?
If I understand you correctly you want to replace the client-to-server encryption offered by HTTPS with client-to-proxy-encryption followed by proxy-to-server encryption without a client needing to trust the proxy. If this would work it would make HTTPS fundamentally insecure since every man-in-the-middle attacker could just do this. So fortunately it will not work.

How to tell if a TLS server requested a client certificate

I'm making TLS client connections in Node.js. Some servers I communicate with request a client certificate. I'd like to be able to detect when this has been requested, so I can log it. At the protocol level I believe this is sent along with the TLS server hello, so the data is there, but I'm not sure how I can get at it.
I'm never actually providing a client certificate for now, I'm just aiming to report which servers requested one.
I think there's probably two cases here:
A cert has been requested, not provided, and the server has accepted the connection anyway (and then probably given my some kind of 'not authenticated' response).
A cert has been requested, not provided, and the server has rejected the TLS connection entirely.
At the moment I can't detect either case, solutions for either or both very welcome.

require('https') vs require('tls')

I'm trying to create a very secure connection between client and server using Node.js, Express.js and TLS (1.2).
I think my problem is in understanding what TLS actually is - meaning what is being exchanged, when and how by who.
Anyhow, I'm searching the internet like a nutter (crazy person) to try and figure out following:
what does var tls = require('tls'); invoke?
what does var https = require('https'); invoke?
I can get tls working when using another node as a client, but in this case the client will be a user in a browser. Can I use both for a browser or only https??
Thanks
Let's indeed start with what TLS is.
TLS is a way to provide secure connections between a client and a server. It does this by providing a safe way for clients and servers to exchange keys so they can then use public-key cryptography to secure their transmission. The exact mechanism is found here, but it's really not important for this answer.
Now, what is https? Well first, let's talk about HTTP. HTTP is a protocol that defines how web servers and clients talk and exchange web pages or data. Basically, it includes a request from a client and the server responds with a numerical message, headers, and (optionally) a body. If you're familiar with writing web pages, this is obvious.
So now, finally, what is HTTPS? HTTPS is a version of HTTP using TLS to secure data. This means that clients and servers can use the same protocol they're used to, wrapped in encryption.
Now, let's talk about these in node.js.
When you use require('tls'), you're only using the encryption layer, without defining the protocol. This will work fine for anything that doesn't expect an exact protocol, such as your other node.js client.
When you use require('https'), you're specifically using HTTP over TLS. The https module is actually a subclass of the tls module! (Oops, actually, the https.Server is a subclass of tls.Server) This means that whenever you're using the https module, you're also using the tls one.
Now, the final question: What does the browser want? If you've been following everything I've said, you can see that the browser wants https. In fact, it's likely that most of the webpages you've visited today has been over https.

Node.js Multiple SSL Certificates

Is it possible to have Node.js use multiple SSL certificates? I am currently using one certificate but had a new certificate issued that matches other domains.
Since my server is behind a load balancer, there are two ways to get to it and I'd like to match them. Is there a way to use two certificates, instead of creating one with both matches?
See this answer for hosting multiple domains on a single https server
In short, you can use the SNI callback from the https server.
SNI stands for Server Name Identification and it is implemented by all modern browsers.
How it works:
The browser sends the hostname unencrypted (if it supports SNI). The rest of the request is encrypted by the certificate. The HTTPs module can then let you decide which SSL certificate is going to be used to decrypt the connection.
SNI Notes:
SNI is used by AWS Cloudfront and other services, if you require a secure connection
SNI requires a modern browser for it to work.. However given that AWS uses it gives me confidence in using it too.
Depending on how you implement it, it may slow down the request.
It may be better to put a nginx proxy in front of this.
Your connection then travels like this: Client -> (HTTPS) -> NGINX -> (HTTP) -> Node
Nginx could also serve static files, which may optimise your site.
I hope this helps you. I am posting this for documentation purposes.

Can a proxy server cache SSL GETs? If not, would response body encryption suffice?

Can a (||any) proxy server cache content that is requested by a client over https? As the proxy server can't see the querystring, or the http headers, I reckon they can't.
I'm considering a desktop application, run by a number of people behind their companies proxy. This application may access services across the internet and I'd like to take advantage of the in-built internet caching infrastructure for 'reads'. If the caching proxy servers can't cache SSL delivered content, would simply encrypting the content of a response be a viable option?
I am considering all GET requests that we wish to be cachable be requested over http with the body encrypted using asymmetric encryption, where each client has the decryption key. Anytime we wish to perform a GET that is not cachable, or a POST operation, it will be performed over SSL.
The comment by Rory that the proxy would have to use a self-signed cert if not stricltly true.
The proxy could be implemented to generate a new cert for each new SSL host it is asked to deal with and sign it with a common root cert. In the OP's scenario of a corportate environment the common signing cert can rather easily be installed as a trusted CA on the client machines and they will gladly accept these "faked" SSL certs for the traffic being proxied as there will be no hostname mismatch.
In fact this is exactly how software such as the Charles Web Debugging Proxy allow for inspection of SSL traffic without causing security errors in the browser, etc.
No, it's not possible to cache https directly. The whole communication between the client and the server is encrypted. A proxy sits between the server and the client, in order to cache it, you need to be able to read it, ie decrypt the encryption.
You can do something to cache it. You basically do the SSL on your proxy, intercepting the SSL sent to the client. Basically the data is encrypted between the client and your proxy, it's decrypted, read and cached, and the data is encrypted and sent on the server. The reply from the server is likewise descrypted, read and encrypted. I'm not sure how you do this on major proxy software (like squid), but it is possible.
The only problem with this approach is that the proxy will have to use a self signed cert to encrypt it to the client. The client will be able to tell that a proxy in the middle has read the data, since the certificate will not be from the original site.
I think you should just use SSL and rely on an HTTP client library that does caching (Ex: WinInet on windows). It's hard to imagine that the benefits of enterprise wide caching is worth the pain of writing a custom security encryption scheme or certificate fun on the proxy. Worse, on the encryption scheme you mention, doing asymmetric ciphers on the entity body sounds like a huge perf hit on the server side of your application; there is a reason that SSL uses symmetric ciphers for the actual payload of the connection.
How about setting up a server cache on the application server behind the component that encrypts https responses? This can be useful if you have a reverse-proxy setup.
I am thinking of something like this:
application server <---> Squid or Varnish (cache) <---> Apache (performs SSL encryption)

Resources