0

I need to create WebSocket authentication mechanism without using ticketing, so the whole authentication needs to be performed via HTTP (over SSL) GET request which is sent to upgrade connection to WebSocket (code snippet used to handle upgrade in NodeJS).

The problem lays in GET request which is not supposed to be used in authentication (mentioned here and here). I would need to send password via path or query parameters in URL e.g. wss://example.com/username/password123 and then validate it on server side.

My idea is to encrypt the password on client side with Argon2 (using salt) and then send it with WebSocket upgrade request (GET) over HTTPS as url path parameter to the server which will validate it with database entry. I know that this question is similar to this one, but it doesn't cover password encryption. Is that enough to say that it's a good and secure approach?

Thanks for help.

Kacper G.
  • 103
  • 4
  • Secure against what? Is you only send a hash, the attacker should not be able to find the original password, but it would be enough to later impersonate you: if the hash becomes the password... Furthermore, for the server to valid the hash whatever the salt, it will have to store the password in clear text... not very good... The good question is what the thread model is. – Serge Ballesta May 11 '21 at 09:16
  • 1
    It's bad practice because GET requests aren't supposed to have an effect on the server side, and browsers and servers will treat those requests as "safe". So that sensitive string might end up in any kind of cache, be visited by bots or prefetched by any kind of service, etc. You should convert that request to POST. – reed May 11 '21 at 09:55
  • @SergeBallesta you're right, I would need to store passwords in the database in plain text, which is terrible. I need to rethink it, it's quite complex to design such a system with such restrictions. – Kacper G. May 11 '21 at 10:03
  • @reed Unfortunately WebSocket handshake must be a GET request – Kacper G. May 11 '21 at 10:03
  • Ok, after some discussion I am allowed to use Cookies, so probably I will set one-secound cookie with hashed login credentials, which will be deleted after first request. The server will verify cookies with hashed and salted entry in the database. I think that using cookies in such case is good idea, or am I wrong? – Kacper G. May 11 '21 at 10:11
  • 1
    Regardless of how you send the hashed password, client-side hashing is rarely used, as there are very few use cases where it makes sense to use it. See https://security.stackexchange.com/questions/8596/https-security-should-password-be-hashed-server-side-or-client-side for more info. – mti2935 May 12 '21 at 13:59

2 Answers2

1

TLS/SSL

When you send password via TLS/SSL, then the URL and parameters are also encrypted, also for the GET method. If the application is the termination point of TLS/SSL, then no other party will see the traffic. If the TLS/SSL termination point is separated from the application and forwards traffic to it, then the whole traffic between the TLS/SSL termination point and your application can be potentially readable by some other parties. In such case the HTTP method does not matter, requests with GET, POST and other methods will all equally be readable for an attacker.

Even if you application is the TLS/SSL termination point, it may log requests, especially request URLs and query parameters. If you overlooked it, passwords may be written to the logs. If the attacker gets access to the log, the passwords will be compromised.

Password hashing

The idea of password hashing is, that if the attacker gets access to the password database, passwords remain unknown and the attacker cannot use them for login.

If you ask client to send password hash, you enable attacks. The attacker that has a copy of password database will just use hashes from the database. The knowledge of real passwords will be not needed. When your application requests password, the attacker will just send a hash from the password database.

Solution

What can you do? There is no single solution. One approach can be following. Make sure, that the whole traffic between TLS/SSL termination point and your application is sent via DMZ.

Estimate the risks: Who has access to DMZ? What devices can access DMZ? What applications operate in DMZ? Etc. Decide, if these risks are acceptable to you.

mentallurg
  • 8,536
  • 4
  • 26
  • 41
0

Not really a direct answer, but way too long to be a comment.

I once had to design a system where I had to securely authenticate over a plain HTTP (not HTTPS) connection using an insecure network. And I finally ended with a manual implementation of a Diffie–Hellman key exchange using asymmetric crypto tools. BTW after the authentication phase, the shared secret was used to crypt and sign the packets (and the packets were of course numbered)

The rationale is that:

  • it only used well known secure implementations (at library level) - roll you own is highly dangerous in security, because the devil hides in the details
  • no secret was ever transmitted in clear text
  • the protocol was by construction immune to replay attacks

My conclusion was that Diffie-Hellman was not used by accident in TLS...

It is slightly more complex to implement than directly sending a secret, and only makes sense if you cannot trust an underlying TLS layer to protect the exchange, but for having implemented it, it is not that hard once you can find a nice crypto library.

BTW, if you want to be super-safe, ephemeral Diffie-Hellman allows Forward Secrecy and is easily implemented with good crypto libraries.

Bruno Rohée
  • 5,221
  • 28
  • 39
Serge Ballesta
  • 25,636
  • 4
  • 42
  • 84
  • Thanks for this answer. I could only imagine how difficult it was to manually set up a secure connection over an insecure network. In my case I am using HTTPS, so I am able to use wss:// scheme. The point is how to properly authenticate a user with a single GET (upgrade) HTTP request. Currently, the only idea which, I think will be secure (correct me if I am wrong), is to use one-time cookie to pass user credentials. – Kacper G. May 11 '21 at 10:48