Can I safely rely on a WebSocket connection after initial handshake? - ssl

The typical scenario:
The client sends his credentials to the server in a POST request using HTTPS.
The server verifies that the credentials are the right ones and authenticates the user. Thus it returns a JWT (JSON Web Token) to the client.
The client opens a non secured WebSocket connection (ws://). So the client and the server now have a channel to exchange data easily (the exact reasons don't matter here).
The user sends any kind of requests to the server through the WebSocket along with the JWT, so the server can verify that these requests are legit.
The server uses the WebSocket channel to return the data asked by the user after it successfully verified the JWT for each request.
Since we used HTTPS, we assume the JWT was not stolen when it was issued (HTTPS could be defeated but let's assume it's sane for our purpose).
The fact that we use a non secured WebSocket means that someone could sniff the traffic of the WebSocket channel and steal the JWT in a heartbeat. So we use a WebSocket Secure (wss://) instead and apply the same previous scenario.
Now that we are using a WebSocket Secure, do we need to keep sending the JWT in each request we make to the server when we use the WSS channel to do so? Or is the WebSocket Secure channel secured enough so both the server and the client are 100% sure (as long as TLS is not defeated) that this channel is legit?
In other words: once a WSS channel has been safely established, can we trust it? (until the connection is closed obviously)
I don't really understand how a WSS connection is established and how it works once it has been established. My understanding is: the critical part is the handshake, and once the handshake is done you can safely rely on the WSS channel (because it prevents MITM attacks using TLS, which WS doesn't do).
I read a lot of stuff these last days about all this but some concepts are still unclear. Any help will be greatly appreciated!

Websockets use a persistent TCP/IP connection.
Using wss is similar to using the HTTPS, which means that once the SSL/TLS handshake is complete, all Websocket data is "wrapped" (usually encoded) in TLS packages.
Assuming the TLS/SSL connection is secure, the Websocket connection will remain secure and could be (and probably should be) authenticated only once.
Hence, there's no reason to keep sending the JWT over and over again. It's a better solution to use the connection's persistent state in order to "assign" a user to the connection.
Side-Note: Although insecure, it would be better to send the JWT once even when using Websocket connection "in the clear" (ws://), since there are less opportunities to sniff out the JWT.

Related

Using socket io over http, is a secure log in procedure possible?

I have built a game server in nodejs using socket io.
I am planning to remove express and cookies from the authentication procedure and instead use webstorage and a client which attempts to log in during the socket io handshake.
However, I am using http and sending the user id and password in cleartext. Please, have mercy on me! I believe using https for the entire socket connection would add a huge overhead since updates are sent every 100ms. My current solution has worked for development, but I am sure it is insecure.
I should mention I have never set up/used https, so correct me if I am wrong regarding the overhead, which I know is a very debated topic. An ideal solution appears to be authenticating users over a https connection and then transmitting game state stuff over http, but I have no idea if or how this could be achieved.
Finally, I have 2 options for logging users in. I could allow the socket io connection on the server and just emit the log in credentials from the client. Then disconnect them if they are incorrect.
However, a cleaner solution would be to send the user id and pw in the http header for the handshake, and then authenticate the user from a socket.io middleware, but I am not sure if sending the data this way would be safe.
I do not think this is such a niche problem that a standard practice does not exist, however it may be to just use https. I believe there is no advantage to encrypting the users credentials as the data can still be snooped between the client and server. Any information on how I can achieve this is appreciated,
Or just point me in the right direction :)
Use one https connection for the login authentication and reply back to the client with a unique security token if the username/password is valid.
Use ordinary http connections for the rest of the dialog between client and server. Include the security token in the dialog if the client is requesting something that requires validation. Your client can store the security token in a cookie if you find that convenient, as the token can only be used for one session.
Have the server purge session tokens once a client signs off, or after the token has been idle for some period of time.
This is cheap and effective for medium-security applications. Variations on this scheme get used in many applications. It is not foolproof - a packet sniffer may be able to grab the security token in transit.
If the security token is constructed from a hash of the client IP address and a server timestamp, then it is easy for the server to validate the token in every message and very difficult for a 3rd-party to hijack the session.

Difference between SSL and JWT

I've been reading and trying to comprehend the differences in browser side security. From what I gather, SSL is used to keep people from sniffing the traffic you send to the server. This allows you to send a password to a server in clear text...right? As long as you are in an SSL encrypted session you don't have to worry about hashing the password first or anything weird, just send it straight to the server along with the username. After the user authenticates you send them back a JWT and then all future requests to the server should include this JWT assuming they are trying to access a secured area. This allows the server to not even have to check the password, all the server does is verify the signature and that's all the server cares about. As long as the signature is verified you give the client whatever info they are requesting. Have I missed something?
You are correct. "This allows the server not to even have to check the password." Why would you have to check a password on each request?
A JWT is a means of verifying authentication. It is generated upon a successful authentication request and hence forth passed with each request to let the server know this user is authenticated.
It can be used to store arbitrary values such as user_id or api_key but they are not very secure so don't store any valuable information here.
Be wary though, if a plain JWT is intercepted by a third party, it can assume this user's session and possible data.
SSL is a lower level form of security, encrypting every request from and to the server to prevent interception and retains integrity.
SSL is achieved by (purchasing) an SSL certificate and installing it on your server. Basically an SSL certificate is a small data file that binds a cryptographic key to an 'organisation'. Once installed succesfully, HTTPS requests (on port 443 by default) are possible.

Send token in every WebSocket (or TCP) request

I'm developing a client-server application which uses WebSocket. I have implemented token-based authentication with JWT. Once my client has a valid token, a WebSocket connection is opened indefinitely.
Is it a good idea to send the token within each request? Is there any chance of anyone to hijack the connection?
My question actually applies to any TCP-based connection which requires authentication.
Is there any chance of anyone to hijack the connection? ... My question actually applies to any TCP-based connection which requires authentication.
Yes it is possible to hijack existing TCP connections or just be the man in the middle when you start a new one. The protection against this is not to send the authentication within each message because these could be simply replicated by the attacker. Instead use encryption, i.e. wss:// in case of WebSockets or TLS, IPSec or similar in other cases. These protect against both active man in the middle attacks (hijacking) and passive sniffing.

PLAIN authentication over SSL/TLS

If I'm connecting to a mail server over SSL or TLS but using PLAIN authentication, is that secure?
Since the SSL/TLS connection is already encrypted, sending the password as PLAIN text doesn't hurt anything. You could encrypt the password as well, but then you're just double encrypting it. In most cases, I would consider that superfluous.
One case I can think of where you would use something other than PLAIN over SSL/TLS is if you choose to authenticate with certificates instead of passwords. Otherwise, I'd leave it at PLAIN.
Ryan is absolutely right if you are sure if you will never use your application without SSL. SSL is at the presentation layer and whenever a socket connection is established, SSL handshake is the first thing that happens which includes host verification, exchange of session keys and creating a secure transport layer. Communication at the application layer happens once this secure channel is established and the data that is exchanged is encrypted using the session keys and hence the communication is anyways secure.
However, if your application has an option to work with/without SSL then you should be encrypting your password separately. While working over SSL, this would be redundant but otherwise it is necessary.

is ssl secure on both ways?

I know that certificates that are sent by the server cant be faked (still there is MD5 collisions but costy) but what about faking the client ..
in man in the middle attack:
cant we tell the server that we are the legitimate client and take data from that server manipulate it then encrypt it again with legitimate client public key ? how does the client be sure that the data came really from the server ?
in theory .. can we inject any data into the response sent by the server to the client ?..
How are you authenticating the client? SSL client certificates? Or some application level system (cookies etc)?
Here's what SSL does in a nutshell:
Negotiates a Diffie-Hellman shared session key between the two parties
Has the server sign the session key and send the result to the client. Once the client verifies this, the client knows there is no MITM, and the server is who they say they are.
If client certificates are enabled, has the client sign the session key and send the signature to the server. The server now knows there is no MITM and the client is who they say they are.
Encrypts all data in both directions using the shared session key
Typically when you use SSL you won't use client certificates. Strictly speaking, the server does not know if the connection is MITM'd. However, most clients will disconnect if the server certificate is bad. The server assumes that if the client pushes forward with the connection, there is no MITM. Even if Mallory, doing the MITM, chooses not to propagate the disconnect from the client, he has no new information now; all he's done is connected to the server himself. Without intercepting the client's session cookie or other authentication information (which is only sent by the client after verifying the connection is secure) the MITM is useless.
So in short, as long as one end or the other verifies the certificate of the other end before initiating any high-level communication of sensitive information, SSL is secure in both directions.
You're right -- without secure certificate authentication on the client and server there is an opening for a man in the middle attack.
SSL can be "secure both ways" if you use mutual authentication also called two-way SSL.