I am creating a client server communication based on Asynchronous Sockets, my client will send the username and password to the server then the server will replay whether the account is valid, so i want to secure this steps so no one could record the conversation and keep sending it to my client to achieve illegal entry to the secret data
[The Question {Simplified}] How to securely authenticate the client to the server ... ?
[NOTE] I know SSL but i cant afford paying for a certificate so i need a free alternative to provide secure communication between my client and server.
As always, the most secure password is the one, that the server doesn't know, and that is never transmitted. So what you could do is:
On the server, store the username, a random salt ("account salt") and a secure hash of the salted password ("server shared secret").
On login, in a first step let the client transmit only the username (not secret)
The server should reply with the account salt (not secret) and a randomly generated session salt (not secret). It is important, that the server generates the session salt.
On the client, salt the password with the account salt and hash it (keep this as " client shared secret"), then salt the result with the session salt and hash it again. Transmit this as an authentication token (not secret)
On the server, take the salted hash from your DB, salt it with the session salt and hash it - if this matches the authentication token, the connection is authenticated. (Client is authenticated to server)
if you want to additionaly authenticate the server to the client, you repeat the procedure: Client generates a salt, server creates token from it by salting/hashing the stored secret.
If you want to authenticate the single requests (not only the connection), salt them with the shared secret and hash them, send this as a per-request authentication field. Since in a valid login server shared secret and client shared secret are identical,both sides should come to the same result, thus verifying the authentication field.
I typically tell people that if they find themselves doing crypto themselves they are inventing security problems. :) The odds are good you're missing edge cases. I would suggest relying on something that exists already and has been heavily secured.
If you're using managed sockets, there is a version of the stream class that does crypto for you (NegotiateStream). I would suggest starting there and seeing if it can do what you need w/o you having to invent your own.
You could use a combination of public and symmetric keys in order to secure authentication.
First send a public key for the client to send his authentication data encrypted in. If the data is valid, you could then have the client generate his own public key, and have both send symmetric keys to each other via each other's public key.
Something like that should work.
I know that this was posted a few years ago, but I thought that I would add my own two cents here now. Things have changed in the last couple of year. This might help some one else.
I do not want to take anything away from Eugen, excellent work.
The best way to encrypt the traffic between your client and your server is still using SSL/TLS. You can now get free licenses from https://letsencrypt.org/.
It sounds like you already had SSL figured out, so I would plug in with the free certs that you get from the above link
Good luck,
- Andrew
Related
We are using Asp.net Identity (currently version 2). For the purpose of local user authentication, the framework expects clear-text passwords. As far as I understand, this is not the safe method to transfer passwords.
A quick answer can be: use ssl to encrypt password transfer, but this is not a viable solution to everyone.
This is what we think:
The logon form is provided with a one-time random token, then it hashes the password, attaches it to the token and hashes it again. The result is sent to the server.
The server has the hash of the password and the random token, concats them together and if their hash equals what the client sent, proceeds with the logon process.
This is not possible with the current api provided by Asp.net identity: It expects raw password.
What should we do? Rely only on ssl? Is there a way to secure password transfer without ssl?
The web relies on https for securing sensitive information like passwords. I'd say follow the standard. Your hashing algorithm isn't as tried and true as decades of https development.
I am part of an indie game developer team and we are working on a project in Unity (C#).
I used Drupal on the backend (PHP/MySQL) and I want to retrieve data from the database to our software.
So for example if I want the user to log in via Drupal's authenticate (server sided hashing of sent passwords), the user needs to submit his username and password via unity WWWForm or c# HttpRequest at first (client).
If I've done my research properly, there are three possibilites to send data securely (please correct me if I'm wrong):
Implement own password encryption/decryption (use Drupal's password hashing after server side decryption)
Implement drupal's hashing method(s) in c# (client)
Buy SSL certificate and go with HTTPS
It's possible to sniff the HTTP connection or decompile the software, right? Do possibility 1) and 2) make any sense then? Would one of the two methods be secure enough?
Is SSL the only way for us to go?
Implement own password encryption/decryption (use Drupal's password
hashing after server side decryption)
Implement drupal's hashing
method(s) in c# (client)
The problem with these methods is that the client side hashed version effectively becomes the password. So if a MITM grabs the hashed version, they can simply replay it to log in.
Buy SSL certificate and go with HTTPS
Definitely. As well as encryption, HTTPS provides assurance that the client is talking to your server and this hasn't been MITM'd and it will also protect against replay attacks (an attacker recreating the login request from their own connection and then acting on the response).
It depends how secure you want things, and how far you believe an attacker would go to intercept a password. For example, if you use client-side password hashing via JavaScript, it is theoretically possible for the JavaScript library to be intercepted as it travels to the user, and modified so that it sends a plaintext copy of the password. This can then be intercepted as it is sent to your server. But, since you are working on a computer game, this may not be very likely to happen.
SSL with a genuine certificate would go some way to preventing this, since it is theoretically impossible for a MITM (man in the middle) attack to sniff, never mind modify, data as it travels down the wire. To do that, they would need to have a copy of your private server key, either by stealing it from your server or stealing/obtaining it from the certificate authority. While this is not impossible, it is most unlikely to happen.
SSL certificates of the lowest security are now very inexpensive, and in general will save you a lot of work thinking about how to implement security. I'd just go with this option.
I am a .Net developer since its first days. But the last time was quite interesting. I wrote an network basics dll for my own purpose and started to write the fitting iOS client apps. Everything works fine but now I kind of thought about not managing the user data myself, but to use the existing data of the Active Directory. It would not be any kind of problem to send the plain text username and password from the app to the server and do the verification then, but that is not as safe as I want it to be. My personal most preferred way would be:
send username from app to server
get challenged password hash from the AD by the username and the challenge
send the challenge to the client
hash the password with the challenge
send back the hash to the server and check if the hashes are matching
Quite simple straight forward way. I do not have to deal with certificates and can provide a basic security. I know, that in modern times it is not the topmost safe way. But it is sufficient for my needs.
My question is, is there a way to get the hashed password for a user from the ad and do I get the challenge? Or is there an other simple way to provide a easy secure way of verifying an user not in the local network?
Thank you very much in advance
Best regards
Florian
Have you tried using System.DirectoryServices.AccountManagement? It's very simple to verify a login:
bool authenticated;
using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domain))
{
authenticated = domainContext.ValidateCredentials(username, password);
}
As you said this should be a basic authentication but without sending plain password over network. Therefor I would suggest a solution with an asymmetric encryption.
Encrypting the password on client side and send the encrypted message to the server. The server is the only one having the private key and could therefore read the password and validate it with PrincipalContexts ValidateCredentials methods (like itsme86 suggests).
So the steps for your application could be:
ask for public key from app to server
get public key from server
encrypt password with public key
send back the encrypted password together with the user name to the server
server decrypts the credentials and validates them against the AD
Is it possible to safely include a password in a query string for a c# asp.net site.
Few assumptions and things I know -
The site does not and will not have links/images/javascript/analytics to/from other sites. So no referrer links to worry about.
ALL communication with the web browser will be over https.
I know that the query string will remain in the history of the
computer.
More than just the password/username is needed to login. So simply
pasting the url back into the browser will not result in a login.
I know the site may be susceptible to cross site scripting and replay attacks. How do I mitigate these?
Given the above scenario, how should I include a password in a query string?
Please don't ask me 'why', I know this is not a good idea, but it is what the client wants.
SSL
You can safely send the password to a web server using a SSL connection. This encrypts all the communication between the client/server.
Hide In The Header
Basic authentication protocols place the user/password information in the HTTP request header. C# and many other web server languages can access this information, and use it to authenticate the request. When mixed with SSL this is very safe.
Register An Application Key
If none of the above is possible, then it's recommended that you create a unique key for each user. Rather then send their password this key is used. The advantage is that the key is stored in the database and can be removed. The user's password remains unchanged, but they must register again to get a new key. This is good if there is a chance someone could abuse their key.
Perform Hand Shaking
Hand shaking is where the client makes a request to the server, and the server sends back a randomly generated key. The client then generates a hash from that key using a secret, and sends it back to the server. The server can then check if the client knew the correct secret. The same thing can be done where the password is the secret instead and the client includes username details in the request. This can authenticate without ever sending the password.
Encrypt Password
If none of the above are possible options, then you could attempt to use JavaScript to encrypt the password before it's sent via an open URL. I found an open source version the AES block cipher. The project is called JSAES and supports 128 to 256 bit encryption. There might be other JS libraries that do the same thing.
It is generally not advisable to put secrets in a query string, which can then be book marked and copied, exposing the password at-rest in history files, cookies, etc.
To just safeguard the password in this use-case, an option would be to hash the password (one-way, not reversible). In this way, the actual password is not known in transit nor at-rest but... it implies that an attacker can still use the hashed value to login to the server that would presumably compare the hash value to its store for authentication.
Update: Switching to stateless (JWT) sessions
In the olden days when buggies were a thing (okay - they are still a thing with some fringe groups but) - we used "sessions".
A "session-ID" (see JSESSION_ID) for example in Java/J2EE/Servlet based systems was stored as a cookie. That value, being a random number, was hard to guess - but it had problems from hijacking to memory and lookup overhead on the server.
In 2020 times (as of this writing) ... JSON Web Tokens (JWT) can be used to securely encapsulate the user-session information and be pushed back down in an immutable cookie without ever exposing the password and with very little server overhead.
In this model, after login, the server issues a token (using OAUTH2 or related), which has an expiration time-stamp.
This data and possibly other session information can then be encrypted, hashed, signed and wrapped up in a JWT (token) - as a cookie back to the web-browser.
Ref: https://oauth.net/2/jwt/
At this point, the client cannot do anything to compromise (or even view) the cookie because any sensitive data should have been encrypted (using AES256 et al or better) and the contents hashed and the hash signed. What this means is that when the server gets the token back, it looks at the timestamp and may throw it out - forcing re-authentication and then...
Can otherwise verify it signed the content, hash the contents and verify the hash and decrypt data if needed (which would not include the password but rather just the ID of the user - which is verified and not necessarily a secret per se).
This can include already-looked-up scopes (authorization) for what the user can do etc - avoiding round trips to the authentication server until the token times out.
Thus the above (using JWTs, hashing, signing, encrypting - into a cookie) is the recommended way to both go stateless and avoid passing around a secret between the client and server.
Ref: https://auth0.com/blog/stateless-auth-for-stateful-minds/
Additionally, consider that multi-factor authentication schemes (see Google authenticator) and related systems are a much stronger security posture (stealing password is not enough and the keys auto-rotate on external systems) but do require semi-frequent access to the rotating key system, which inhibits a smooth user experience to some extent.
Update: Multi-Factor auth by Google and others has gotten much better.
Older companies still use SMS one-time-passwords (OTP) ... which can be compromised by going to a wireless company store and claiming SIM card loss (given a known phone-number).
Google and other more advanced companies comparatively use rotating tokens that can be embedded in a smartphone app that then are used for many services.
Google even has push-notification where user just confirms by button press: "Yes - it is me".
I have an application which exposes service which is consumed by the web application via Jquery POST and other applications (IPad, Android, etc). I have to create an authentication system which is highly safe but still fast enough.
I thought of making a token which will be passed to the application on login and which will be used for a specific amount of time (say 30 mins) post which it should refresh itself and not expire the session. So I thought of making a token being sent to service and which will generate token. It will accept
UserId
Password (both encrypted with public key)
AppId
The server will decrypt the request by the private key and generate a token which will be valid for a specific time. Now since this would highly depend on the private key (which will be same and thus someone from within system can leak it and misuse it) so i want the private key to be refreshed after a specific time (say 2 hrs).
Question -
How do refresh Private key and ensure that the currently issues tokens will not be rejected.
Is there a better way of doing it
Is there a better way of doing it?
Yes there is, It's called SSL/HTTPS. If you are already using HTTPS then there is no need for any of this crypto-magic. If you are not using HTTPS you are already insecure by design and nothing you come up with will fix that short of re-inventing SSL.
So what should you do if the transport is secure (HTTPS)
Client makes a request for authentication sending username + password in plain-text.
Server verifies the username + password pair against the (hopefully) hashed password stored with the account.
Server responds with a token (encrypted account id, expiration, etc) using a static AES key.
Client uses the token for all authenticated requests.
Easy.
One thing you could do...
To prevent loss of credentials used on non-secure devices you should take a page from Google and others. Rather than having users entering their website passwords, make them visit and log in to your web server. From there they click a 'generate access token for device'. A unique data string (20 or more characters) is generated and recorded with their account. This 'alternate password' can then be revoked by the user from your website.
How can I make this more secure?
You really can't do much better, here is why...
Assume an attacker gains access to your private key. The attacker can then replace your server or play man-in-the-middle while stealing usernames and passwords.
To attempt to prevent this you contrive some PKI exchange to send the password encrypted by a public key the server gave you. I as a man-in-the-middle can simply give you my own public key and access the username and password and then if I choose, forward it to the real server.
--or--
To attempt to prevent this you use some salt + password hash that will be sent to the server in place of the password in clear text. I as a man-in-the-middle can simply give you a fixed value for the salt and then pre-compute a complete rainbow table for that salt value. Now I again have everyone's password (well most) in clear text.
--or--
To attempt to prevent this you use PKI to establish some secret session key and then sign and encrypt every communication. Well, gee... that sounds familiar... see SSL on Wikipedia. Realize that the ONLY thing that makes SSL secure is the protection of it's private keys. Once a private key is lost, all security and trust is lost.
Final notes:
Without being able to protect some encryption key you cannot build a secure communication.
You should also be aware that thousands of man hours have been spent on software implementations of SSL (like OpenSSL) and they constantly find vulnerabilities in their implementations. Your hope of implementing this yourself, and doing it as secure as IIS or OpenSSL, is almost NIL. That is not a Digg on you, that is just reality, I couldn't do it either I only know enough to not even try.
Lastly, my final advice is about your statement: "someone from within system can leak it and misuse it". This is your real problem. Fix that and all else will be much easier. Securing a server environment should be your first priority. Your second priority should be minimizing the impact to your customers once you fail to do the first.
Some helpful links:
How to generate password using a specific set of characters.
Another example of how to store a salted password hash.