Mimic browser TLS fingerprint in node websocket - node.js

How can I get a TLS/JA3 fingerprint, which mimics a major browser, in a websocket connection from node? Can I achieve this by modifying node’s TLS configuration, or do I need something more complex?
I've already tried passing shuffled ciphers as one of the options, along with the headers, using node.JS's ws library, however this wasn't enough achieve the desired effect.
Some libraries allow for single HTTP requests, e.g. this one written in the go language, but I need an open websocket connection.

The JA3 fingerprint is based on ciphers and order and various TLS extensions and order. While ciphers and order can be changed, features like the TLS extension order are not accessible from node - I don't think there is even a OpenSSL API for this (OpenSSL is the TLS library underlying node). This means there is no way to emulate a specific JA3 fingerprint from node.

Related

Difference between OpenSSL TLS/SSL versions

I am currently implementing OpenSSL's TLS/SSL standards into my mail service, allowing my users to select the TLS/SSL version they want. Here is the list of versions:
["TLSv1","TLSv1_server","TLSv1_client","SSLv3","SSLv3_server","SSLv3_client","SSLv23","SSLv23_server","SSLv23_client","TLS","TLSv1_1_server","TLSv1_1_client","TLSv1_1","TLSv1_2","TLSv1_2_server","TLSv1_2_client"]
I did some Googling on what the difference of the options are, and I understand that some versions are deprecated, or shouldn't be used because of security issues, such as TLSv1. I don't understand the difference between the client vs server ones, but from my own testing, the server options return errors when trying to send a mail with it.
So my question is - of that list, what should I remove?
What you show are not SSL/TLS versions but various types of SSL contexts which also include the usable SSL/TLS versions. This means the *_server "versions" are all SSL contexts which should be used on the server side where you usually also need a certificate. The *_client variants are for the client side of the TLS handshake, i.e. the one which initiates the TLS handshake.
Within a mail client you don't want to use any server specific SSL contexts because with these the mail client would expect the peer to start with the TLS handshake which it does not.
For more details see the man page of SSL_CTX_new which has a detailed description of what all these different contexts mean.
... allowing my users to select the TLS/SSL version they want.
While your specific implementation is wrong the idea of letting users chose the protocol version is wrong too. Instead you should just use a generic context without limitations (apart from disabling insecure versions) so that it automatically picks the best protocol version during the TLS exchange. Selecting specific protocol versions should only be done in case the peers TLS stack is broken, like for stacks which simply refuse a TLS 1.2 handshake instead of replying with TLS 1.0 in case they don't support TLS 1.2.

Does Node.js honor HPKP/support certificate pinning?

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.

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.

How to export master secret from browser SSL/TLS session?

I'd like to open a browser in Windows, go to an HTTPS site, and perform a sequence of actions while capturing packets with Wireshark. Then I want to use the encrypted packet capture to view the decrypted HTTP traffic. I know of many ways to do this (listed below) if you forego the browser, have access to the server, or add a MITM, but none of these work when you're restricted to the scenario above. Here are my typical approaches:
Server: For sites where I have the server private key, use Wireshark's built-in SSL decryption.
MITM: An SSL proxy (e.g., Burp suite) will allow viewing of decrypted traffic, but this requires using a different certificate and key pair than what is used by the server.
Browser: openssl's s_client can connect, make requests, and export the master secret, but this does not display the associated web pages or run javascript to compute subsequent request parameters.
Is there a way to export the master secret from a "normal" browser so that I can use it to later decrypt a packet capture of the browser session?
For example, is SSL/TLS state stored on disk when a browser is closed? If so, how would I access it? Is it accessible in memory while the browser is running (and if so how would I find it)?
Or, is all SSL state data stored by the OS (Windows) and not accessible directly?
Alternatively, is there a way to force a browser to use a particular master secret (and any other associated SSL state data like session ID, etc.) for a particular HTTPS connection? If so, I could set up the SSL session using s_client, and then transfer the key data to the browser and open a new connection in the same session. This would accomplish the same goal through different means.
For browsers that use the NSS library (e.g. Firefox) you can set the SSLKEYLOGFILE environment variable, which will cause NSS to save the necessary secrets. You can then directly use that file with Wireshark. There's more information to be found here.

Applying manual AES encryption instead of using HTTPS

Due to a couple of issues with my host, I'm unable to use a SSL-certificate on my server (I'm not ready to change provider just yet), and can't therefore use HTTPS. This server will communicate with a couple of client-computers and will transfer data that's somewhat secret.
Would it be reasonable to simply use AES encryption (encryption on client before sending, decryption on server before processing) instead of HTTPS?
This depends on your deployment environment.
Replacing SSL/TLS (and HTTPS) with your own encryption protocol for use by a web browser is always a bad idea, since it relies on JavaScript code delivered insecurely (for details, see this question on Security.SE, for example).
If the client isn't a web browser, you have more options available. In particular, you can implement message-level security instead of transport-level security (which is what HTTPS uses).
There are a number of attempts to standardise message-level security with HTTP. For example:
HTTPsec had a public specification (still available on WebArchive), but a commercial implementation. I'm not sure whether this has been widely reviewed.
WS-Security, oriented towards the world of SOAP.
Perhaps more simply, if you want to re-use existing tools, you could use S/MIME or PGP (in the same way as you would for e-mails) to encrypt the HTTP message entities. Unlike HTTPS, this won't protect the URL or the HTTP headers, but this might be enough if you don't put any sensitive data there.
The further down you go with "raw encryption" yourself (using AES directly, for example), the more likely you'll have to implement other aspects of security manually (typically, verifying the remote party's identity and dealing with the problem of pre-sharing the keys).
If you have a small list of clients that don't change often, you could implement your own SSL-Tunnel using SSH. On the clients do a;
ssh -D 4444 nulluser#example.com -N
where nulluser has no shell or file access on example.com.
Then add a foxyproxy whitelist setting - so that for example.com the client browsers use the localhost:4040 proxy.
It's a hack, it's totally unscalable, but it would work as I say for a small, static number of clients, and it has the advantage of not reinventing any wheels while being totally secure.

Resources