How to build a fully secure login: do I need SSL? - node.js

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.

Related

How to do authentication over web sockets?

Why am I using websockets?
I'm working on routing all my HTTPS requests via a WebSocket, because my app has a chat feature and I need to keep the WebSocket open when the app is running, so why not just route all the requests through it.
My problem.
This turned out to be easier said that done. Should I use the same Access token & refresh token to verify client authentication. Or should I just verify it when the connection opens and then trust it for as long as it's open. So here are my questions:
Is wss(Web socket secure) enough to stop man in the middle attacks?
Should I generate a ticket sort of mechanism for every WebSocket connection, that lasts 2 - 10 minutes and then disconnect and ask the client to reconnect?
Or should I have a Access Token with every request from the client.
How to I make sure that when the server sends the data it is going to the right client.
Should I just end to end encrypt all the payloads to avoid a lot of problems?
Or should I just verify it when the connection opens and then trust it for as long as it's open.
That is fine as long as the connection is over a trusted channel, e.g. ssl/tls.
Is wss(Web socket secure) enough to stop man in the middle attacks?
Yes. Wss is simply ws over ssl/tls.
Should I generate a ticket sort of mechanism for every WebSocket connection, that lasts 2 - 10 minutes and then disconnect and ask the client to reconnect?
I'm not sure why would you do that. On the contrary, with chat-like app you want to keep the connection open as long as possible. Although I advice implementing ping calls on the client side and timeouts on the server side. With such approach you can require action on the client side every say 30s.
Or should I have a Access Token with every request from the client.
Not necessary. With ssl/tls you can authenticate the entire connection once and just remember on the server side that is authenticated. Tokens are used with the classical HTTP because it is easier to scale horizontally such app, e.g. it doesn't matter which server the connection goes to, you can even switch servers between calls and that won't affect auth. But with chat-like app (or any app that requires bidirectional communication) the connection has to be persistent to begin with, and thus tokens introduce unnecessary overhead.
How to I make sure that when the server sends the data it is going to the right client.
I'm not sure what you mean by that. That's pretty much what tcp + ssl/tls guarantees anyway. It is the same for any other protocol over secure tcp. Or do you mean at the app level? Well you have to match a user with a corresponding connection(s) once authenticated. The server has to track this.
Should I just end to end encrypt all the payloads to avoid a lot of problems?
What problems? E2E encryption serves very different purpose: it guarantees that you, a.k.a. the server, is unable to read messages. It guarantess high level of privacy, so that even the server cannot read messages, only peers. And so this is a business decision, not technical or security decision. Do you want to have full control over conversations? Then obviously you can't go with E2E. If on the other hand you want to give the highest level of privacy to your users then it is a good (if not mandatory) approach. Note that full featured E2E is inherently more difficult to implement than non-E2E.
I need to keep the WebSocket open when the app is running, so why not just route all the requests through it.
That is an interesting approach. I myself am thinking about doing that (and most likely will try it out). The advantage is that entire communication goes through a single protocol which is easier to debug. Another advantage is that with a proper protocol you can achieve higher performance. The disadvantage is that the classical HTTP is well understood, there are lots of tools and subprotocols (e.g. REST) covering it. Security, binary streaming (e.g. file serving), etc. are often managed out of the box. So it feels a bit like reinventing the wheel. Either way, I wish you good luck with that, hopefuly you can come back to us and tell us how it went.

Should I double validate data exchange between server and client (mobile)?

My server send some data to the mobile app
The user does some operations with those data and sends other objects back to the server, which contains the data that the server first sent (PS: of course those objects are created by the mobile app through user interaction)
Before the server persist mobile's data, should I validate if the server data inside it is consistent? Because if it's not, it will cause a exception.
But if you know it will cause a exception, why don't you avoid it?
Because I'm relying on:
Mobile app to be working 100% and send consistent data
Authentication between requests so it's not forged
Extra overhead checking something that normally would be OK, unless someone hacks it
Yes, you should validate and sanitize all inputs on the server side. Authentication doesn't help with integrity. If I am an attacker, I can make HTTP requests using CURL bypassing any security control you may have in your app.

Socket.IO Sign In

So I have an application which uses Socket.IO, and the client connects to the Socket.IO server using a token generated by the web server when the client made a request. This should mean that they Socket.IO connection is now secure for this user.
I was wondering if it was practical to do user authentication (signing in/out) through Socket.IO alone meaning no POST. The client would send send an event like io.emit('authenticate', { ... sign in data ... }); and the Socket.IO would check the credentials and if it was verified, it would manually set the session data through the session store.
Is this way of doing this secure, or should the traditional POST for signing in/out still be used?
Doing it via Socket.IO is just as secure as an HTTP POST simply due to the fact that an HTTP POST has zero security built into it. You need to make sure that this process is secure and neither HTTP POST nor Socket.IO will help you with that at all.

How to authenticate with express and socket.io with TOKENS and not with COOKIES.

I'm building a realtime mobile app (native) and I'm interested in starting the app from a user login screen and then move on.
I figured I need Express + primus with socket.io (or sockjs) + passport.socketio + redis (not 100% sure I need redis yet) to build my backend.
I even found this step by step tutorial which is really helpful, it takes me step by step to making a secure api.
My question is a double one:
How can I tweak this example to use TOKENS instead of cookies (since I'm building a native mobile app and not a browser web app) and its more secure according to this.
How to bind express with socket.io - in other words, how does socket.io get to know if the user is authenticated or not?
I welcome any comment or advice.
Thank you.
First, I would use a different websocket library instead of socket.io. The socket.io developers are currently working on engine.io and socket.io appears to not be very actively maintained. I've experienced many of the issues described in the following links and since moving to sockjs have not had any problems.
http://www.quora.com/Sock-js/What-are-the-pros-and-cons-of-socket-io-vs-sockjs?share=1
https://github.com/LearnBoost/socket.io/issues
https://github.com/ether/etherpad-lite/issues/1798
http://baudehlo.com/2013/05/07/sockjs-multiple-channels-and-why-i-dumped-socket-io/
You may have to implement your own custom events on top of sockjs, but that's pretty trivial. Since it sounds like you're already using redis then implementing rooms and pub/sub should be pretty easy too.
Here's how we do our token based socket authentication.
First the client makes an HTTP request to the server to request a token. This routes the request through express' middleware and gives you easy access to the session data. This is where you would interact with passport to access their account or session data. If the user is logged in then generate a UUID and store their session data in redis as a key/value pair where the key is the UUID and the value is their stringified session/account data. Only send the UUID back to the client.
When the client first creates a websocket connection set a flag on the socket that marks it as unauthenticated.
When a message comes in on a socket check to see if the socket is authenticated. If not then check for a token in the message. If it doesn't exist then kill the connection. If it does then query redis for the key/value pair keyed by the token. If redis returns any data then you now have the session data for that user and can attach it to the socket and mark the socket as authenticated. If there's nothing in redis keyed by the token then kill the connection.
Now when you perform any operations on a socket you should have access to the session data for that user.

Flex/Air secure client-server communication

I am looking at ways to implement a safe client-server communication via HTTPService requests in Flex/Air. The server side is implemented in PHP, whereas the client could be running on a desktop (Air) or on a browser (flex).
The simply usecase that I need help to secure is -
Desktop client sends a request to the server and gets a response
How can I ensure at the server side that the request is being sent from a valid client? From what I could research, Flex doesn't allow for manipulation of request headers so I am failing to manipulate them. All request queries can be seen by using any network monitor, so having a unique (yet static) parameter won't really hit what I am trying to achieve.
On the other hand, the server can be mimicked by simply manipulating the hosts file. At the client end, how can I ensure that I am receiving the response from the actual server and not from an alias added to hosts file
My solution is to encrypt and decrypt data on the both sides.
In the Air data you need to send should be encrypted with as3crypto and send to server where PHP whould decrypt it, Look here in the last post for the working code example decrypt a as3crypto encrypted text in PHP, you can do the same in case of server to client communation.
So you need to keep same Key and IV for both server and client sides, To be more secure you can embed them as binary data in the project http://www.ghostwire.com/blog/archives/as3-embedding-binary-xml/, it's wouldn't be easily viewable for AS3 decompilers, but anyway take for the notice that it might be hacked by the advanced guys.

Resources