I am doing experimenting in nodejs. I'm trying to use a TLS Ticket to resume a TLS Session. So I will make a client save off the TLS Ticket after successful connection. After shut down I would like it to use the same TLS ticket to reestablish the TLS connection.
I have found the node tls command tlsSocket.getTLSTicket() however I am not sure how to use it to reestablish a connection because it's "Useful only for debugging".
What i want is the ability to get the TLSTicket from the client and manually validate it against a TLSTicketKey in a server in nodejs.
Thanks
After spending way more time than I should have, these are what I found:
There doesn't seem to be any API or exposed JavaScript functions that would allow you to validate TLSTickets.
Reusing sessions via session tickets works out-of-the box, the implementation is completely transparent for your node.js
https://strongloop.com/strongblog/improve-the-performance-of-the-node-js-https-server/
However, as you will see in the link, it is possible to manually handle sessions with a session store (which obviously defeats the purpose of TLS tickets).
Node uses the following function provided by OpenSSL to do Ticket processing.
SSL_CTX_set_tlsext_ticket_key_cb - set a callback for session ticket processing
Full Details: https://github.com/joyent/node/blob/d13d7f74d794340ac5e126cfb4ce507fe0f803d5/deps/openssl/openssl/doc/ssl/SSL_CTX_set_tlsext_ticket_key_cb.pod
It's done from here: https://github.com/joyent/node/blob/master/src/node_crypto.cc
Node does not emit resumeSession when it receives valid TLS ticket.
The following GitHub issue describes why and is an easy reference to Node's TLS ticket implementation details.
https://github.com/joyent/node/issues/5872
Related
Currently the TLS Session Resumption documentation for Node.js only covers two methods (Session IDs and Session Tickets) both of which are obsoleted in the TLS 1.3 spec. In practice I've found that Filezilla is not utilizing either of these methods over TLS 1.3 when the server is configured to handle them.
That was confirmed to me by a Filezilla team member, they only utilize the Pre-Shared Key method as specified in TLS 1.3.
Which brought me to the PSK docs, which are sadly even more sparse and dated than the session resumption docs. They don't even cover exchanging a PSK during the handshake and instead focus on out of band PSK. I've been digging through the Node source but am not finding anything very helpful since most of this stuff is in the deps -> OpenSSL and my skills at deciphering C are not great.
It is quite possible that my question is not suitable for this medium, if so I understand if it is closed. That said, my question is simply: Can PSK based session resumption be achieved in Node.js at all at this point and if so, what would that flow look like?
context
I'm building a project to better understand login/security, and SSL is really tripping me up.
So far I have a front end (vue.js), an API (node/express), and a DB (postgreSQL).
This is the general auth flow:
When a user logs in they send an email and password (via Axios) to the API.
The API queries the database for a matching username and then using bcrypt.compare it checks the password that is hashed in the database.
If this is successful, the API signs a JWT and sends it to the client.
The client then saves the JWT in local storage and is used for future queries.
question(s)
So far I think that all of the above is the best practice EXCEPT for the first step. From the reading, I've done so far the client needs SSL to securely send a password to the API. Is this the case? Does my server also need to be SSL or just the client/host?
I'm ultimately going to try to use firebase hosting (which is automatically SSL) for the frontend, and heroku for the API and database. If there are more secure options I'm open to suggestions.
Also, in general, I'm new to all of this security stuff - If I'm missing anything or if something else isn't secure, I would love the advice!
SSL creates a secure connection between two points. In our scenario between the client, and the server. After some initial negotiation, the client encrypts its messages in a way that only the server can decrypt. And the server does the same with its answers, or its own questions. By using SSL between these two end points, nobody but the client and server can read the messages.
This is important, since a message sent between client and server is actually seen by many more machines/processes in between. Dozens of other processes can thus see the message, and if the message is not encrypted that means all those processes can know exactly what's in the message. When the client and server communicate over SSL, the other processes still see the messages, but they can't decrypt them.
To your concrete questions: the client opens a secure connection to the server. Both the client and the server need to support this. If you write a custom server, that means you'll need to ensure it has a SSL certificate. A very common place to get these for free these days is letsencrypt.org.
I have a custom TCP server implemented with Python 3.5's asyncio library. I also use Lets Encrypt certificates for SSL encryption of the communication with the server. Lets Encrypt only issues certificates valid for 90 days and there is a good chance my server will not be restarted for a longer period of time than this.
I am generating the SSLContext like this:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ssl_context.load_cert_chain(certfile='path/to/cert', keyfile='path/to/key')
And the server like this:
server = asyncio.streams.start_server(self._accept_client, ip, port, loop=self.loop, ssl=ssl_context)
When the certificate expires, existing connections continue to function but new connections will (correctly) fail. Apparently the SSLContext or the server itself keeps the certificate and key files loaded in memory because updating the files on disk does not solve the problem.
I've read the Python documentation quite a bit and found no solution mentioned. One idea I've had is to try call the ssl_context.load_cert_chain() on a regular interval with the hope that this will update cert and key. I can't look at the source of the load_cert_chain function to determine it's behavior as it is apparently written in C, and the documentation doesn't specify the behavior of calling this function once the context has been passed to the server.
Is there a way to update the certificate and keyfile loaded in the SSLContext at runtime without completely stopping and restarting the server?
I am fairly sure that keeping a copy of the context you use and calling the method to reload the cert chain will work fine. At least at the C openssl API level that's a reasonable thing to do and it doesn't look like python does anything to break that.
As far as I know, there is no API in asyncio.Server to update the SSL certificate when the server is live, you've got two solutions:
You can use the SNI callback to update the certificate during the SSL handshake, but it will only work with clients supporting SNI.
This means that for each client supporting this feature, a callback of your choice will be called and may return a SSLContext object that will be used to establish the connection with the client. You can make this callback so it will read the certificate/key files at each call, or be reloaded when needed by a trigger of your choice.
To setup the callback, see: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.set_servername_callback
The other solution is more complicated to get right with the current state of the asyncio API: it might break if the internal implementation of asyncio changes, and I didn't check how it would work with a proactor loop. However, it will work with any kind of client.
You can create a new server with the new context, but using the socket of the first server:
# This will create a new server with the current socket, and setup what's required to use the new callback.
new_server = await asyncio.create_server(callback, None, None,
sock=old_server.sockets[0], ssl=new_context)
# Ensure that when cleaning the old_server, it doesn't try to close the socket we kept
old_server.sockets = []
old_server.close()
await old_server.wait_closed()
At one point during create_server(), asyncio will start to answer to new connections with the new ssl context. Note that once a connection is started and passed to your callback (_accept_client), it is in practice independent of the server which called it, so it will left any existing connection untouched.
I'm trying to implement a server that can field a request from a very constrained client that wants to handshake using pre-shared keys (PSK) using the cryptosuite TLS-PSK-WITH-AES-256 with a node.js server. I can't seem to find any samples or documentation that talks about how you'd set this up. Is this cryptosuite supported by node.js? If so, how does one go about configuring the options for the https server to accept these connections and verify them?
Although tls.getCiphers() claims to support psk-aes256-cbc-sha, it appears that support is not actually implemented.
Someone did submit a pull request implementing PSK several years ago, but it apparently went stale and was never merged.
To get PSK working, you'll have to manually apply the changes from the old PR to the current version of node and create a custom build.
I am using dnode as an RPC-style library within my Node.js application.
Now I would like to have secure dnode's connection using public-key-cryptography. I guess that this should be possible anyhow using Node.js' TLS module, but I have never used that, hence I am missing some experience with that.
Has anybody already done this, and can provide a small, but complete example on how to set up an encrypted and secured dnode connection?
Substack has an example on the upnode page
https://github.com/substack/upnode/#ssl-stream-example
So for if you want to use dnode, just swap upnode out
Okay, I got it.
All you need to do is to create a TLS server / client and pipe its stream to dnode.
For an example see my question How to verify that a connection is actually TLS secured?