How to authenticate client based on possession of symmetric key? - security

Our clients call our web service over SSL and authenticate themselves with a username and password. Our server then generates a symmetric key and sends it back to the client.
Then, the client establishes a TCP connection to our server, and sends a login message. At this point, I want to authenticate the client.
My idea is to have the client encrypt a well-known/static piece of text with the symmetric key and use this as proof that it is in possession of the key.
Since the symmetric key is generated randomly, is it ok that I use a static piece of text here?
Any input appreciated.

SSL is built to authenticate both client and server, and asymmetric cryptography the most secure primitive you can use in this scenario. Symmetric ciphers can be used for authentication by using a Cipher Block Chaining Message Authentication Code other wise known as CBC-MAC mode. The use of CBC-MAC has similar protection as an HMAC, but utilizing a symmetric cipher instead of a message digest function. CBC-MAC mode is used by WPA to protect wireless networks.

Your idea is subject to a replay attack - if someone observes a user logging in, they can store the static-text-encrypted-with-symmetric-key and use it later to authenticate themselves.
The accepted way of doing this is a challenge/response. The client connects, the server generates a random challenge and sends it to the client, and the client responds with the encrypted version of the challenge (although you should actually use a HMAC here, rather than a block cipher, because otherwise your client is effectively a one-block decryption oracle!). It would also be safer to use two different random keys (provided at the same time over the web service), one for encryption and one for authentication.
Note though that this scheme, as written, is still susceptible to a man-in-the-middle attack. You are definitely better off using SSL, as The Rook suggests. This will require your client to generate a public key and send it to the web service. The web service responds with a signed certificate containing the client's public key along with the client's unique identifier (username, or whatever) in the DN field. The server on the separate connection verifies the client certificate used (ensuring it's signed by your web service), and verifies that the client identifier in the certificate matches the client that is asking to connect.

Related

How are passwords securely shared between the client and server?

Usually when a user logs in, the user details are sent to the sever to authenticate the user. How are these credentials protected in the best way during flight?
Main Questions :
I understand the passwords are many times hashed, keeping them secure. Also TLS maintains the in-flight security, But is that the only way the transaction details are kept secure or do websites add any of their own layer of security?
In our case, we want to send a passcode to the backend, where another API will be called (that uses password grant) of a third party application. We cannot hash the password, we'll need it in the backend. Will TLS be sufficient for securing it in flight?
We were also planing to implement and secure the passcode by RSA (public key) on the client side and unlock it on the backend for use. Should we consider RSA?
I understand the passwords are many times hashed, keeping them secure. Also TLS maintains the in-flight security, But is that the only way the transaction details are kept secure or do websites add any of their own layer of security?
There are very few cases where layering more cryptography on top of TLS are beneficial. Your case doesn't seem to fit them. So TLS should be enough. TLS already provides encryption in transit. RSA would do the same. Defense in depth means layering different security mechanisms on top of each other.
You might hash the password on the client side creating an intermediate password, but considering your 2. question, this is not what you can do.
In our case, we want to send a passcode to the backend, where another API will be called (that uses password grant) of a third party application. We cannot hash the password, we'll need it in the backend. Will TLS be sufficient for securing it in flight?
Yes, but let the client (your server) validate the certificate chain and don't accept protocol downgrades.
We were also planing to implement and secure the passcode by RSA (public key) on the client side and unlock it on the backend for use. Should we consider RSA?
No, just use TLS 1.2 or higher with a valid server certificate and let the client validate the certificate chain (browser does that automatically for you).
Keep in mind that TLS needs a trust root. Most client side libraries as well as many browser use the trusted root store of the operating system. A certificate chain presented by the server should end in one certificate that is in the trusted root store.
You could use a self-signed certificate, but then the client would need to pin the public key of that self-signed certificate.

How to guarantee that messages received by server are from a client running my app?

I'm wondering how I can guarantee that messages received by the server are definitely from a client that is running my app on their smartphone.
Messages sent by clients running my app will be secured by SSL encryption, so would a good solution be to include some sort of secret key that is stored on the device and on the server, that is then embedded within the message body? (but then this key is prone to being discovered through reverse engineering)
Well, no, if you cannot trust your code and if you do not have access to some kind of protected key store (that performs it's own encryption, e.g. a TPM or suchlike) then anybody can steal the key. If you require authentication you can of course use the normal authentication methods such as user passwords.
If you require the messages to be protected you can then derive a key from the password (using a PBKDF such as PBKDF2 for instance), decrypt a private key with it and use it to sign the messages. If that's too slow, you can use the private key to encrypt a session key, and use a message authentication code.

TLS man in the middle security certificates

First of all, I apologize for sending yet another question about this seeing as there are so many related posts. After reading through them and related sites I'm still not clear on a few points.
Browser connects to server through secure socket
Server responds with its public key with its certificate. This is the step I have the most trouble with. In this message from server to client, can the certificate be easily separated from the server's public key? If it's a root certificate (one which is already included in the browser) then a man-in-the-middle can't fake it, but what if it's not? Can't whatever this online mechanism the client uses to verify the certificate be hijacked? Furthermore, if the client's computer is compromised, the root CA's can be compromised, right? Any steps that avoid this? One last thing: It is said that a certificate is insecure until signed. I can't figure out what this means, especially since a certificate can sign itself. I think it's supposed to mean that someone is assuring the authenticity of the message, so a certificate signing itself sounds insecure ("Are you a REAL certificate?"..."ummm, sure, sure I am"). If the mechanism for authenticating a certificate is the internet, I'm wondering how is that secure. Is signing a certificate the same as thing (literally) as saying the client verifies the certificate?
Session key is encrypted with public key and sent to server. This session key is a symmetric key that both server and client will use for remainder of encrypted communication.
I must say, most information online is so vague. So many holes in explanations and hand-waving going on. My guess is that very few people know the actual mechanisms very well?
You've left out several steps. One of them is that the server sends a digital signature over the entire handshake so far, signed with its private key. Only the server can do that, with its own certificate. Nobody else's. The client verifies the digital signature using the public key in the certificate that was sent. That proves that the server owns the certificate. It also proves that the server is the same entity that sent all the other handshake messages.
BTW your step 3 is imaginary. The session key is never sent at all. It is computed independently at both ends.
EDIT Comments on your answer:
Server (from JoesGoods) gets a certificate from the CA via?
Usually via an Internet browser.
Can this be hijacked?
No more than any other secure SSL session can be.
The certificate is "signed"
Correct.
which means a bit of it is encrypted using the CA's private key.
No. You made that up.
Specifically the bit that has the web server's info (JoesGoods' server info)
No. You made that up.
The entire certificate is signed, and that does not mean 'encrypted', with the CA's private key.
Bob's browser connects to server through a secure socket and sends a "hello" packet.
The socket isn't secure at this point. It's just plaintext.
The server sends its public key and certificate to Bob.
No. The server sends its certificate. The public key is already inside the certificate.
the browser checks that the webserver (JoesGoods) matches what's in the signed portion of the certificate
The entire certificate is signed. The client checks that the server it is connecting to matches the subjectDN of the certificate.
The webserver's public key is also signed with the CA's private key
Because it's in the certificate. Otherwise there is no other way this can be accomplished. That's why it isn't sent separately, and it's also why the entire certificate is signed, not just the bits you like.
The browser sends a client key exchange packet to the webserver (JoesGoods) using the webserver's public key included in step (2).
This part is cipher suite-dependent. What you have described applies to RSA cipher suites. Diffie-Hellman is a different story, and there is room for expansion to include others.
This client key is used to generate symmetric keys to conduct the remainder of the exchange. This client key is called a "premaster secret" and is a random key. Since the symmetric keys are created using this key, I wonder why not just send the symmetric key itself since the connection is encrypted and validated at this point.
Because it wouldn't be nearly as secure.
You also have some of these steps out of order.
I really don't see the point of enumerating all these steps informally when they are already completely specified in RFC 2246. There's enough misinformation about TLS floating around the Internet already, such as this piece of unmaintained drivel.

Sending pre-encrypted data through SSL

A client need to be authenticated by the server, so it need to send credentials. The credentials can be stored in a client database as in encrypted form. Since the server's certificate is known, in order to provide best security the client can use the public key of the server to encrypt the password. But the problem is now how to send the password without double encryption.
For example, suppose the server's authentication URL is "https://example.com/a?u=user&p=password", so the client have to send the SSL-encrypted data of this string to the server. Since the client stores only the encrypted password, it must find a way to send ssl_encrypt("https://example.com/a?u=user&p=")+pre_encrypted_password as a whole to the server.
The client is using WinHTTP api, so are there any way to achieve this?
No. SSL does not work that way - data sent over an SSL connection is encrypted using a symmetric cryptographic algorithm (usually AES, RC4, or similar), using a key that is established during the initial SSL handshake. The public/private key of the server are only used during the initial handshake; after that, they are not used.
Anyways, storing the password this way does not make it any more secure. If it's stored in an encrypted form that can be sent to the server, anyone who managed to get it would be able to use it that way; that encrypted form is password-equivalent, so it's no better than just storing the password!
Potentially you can save the certificate sent by the server (assuming that this certificate has RSA key which allows encryption), then use it in PKCS#7 encryption of your data, and send the encrypted data to the server. There's another question that appears - does the server-side code have access to the certificate. This is not the case in many configurations. So the server won't be able to decrypt the data.
Also, as pointed by EJP, this does not make much sense as you will be double-encrypting the data with merely the same key (technically keys will be different but the added security level will be minimal).

Login Authentication Mechanism - Proper way for client to send username/password

I am curious how to properly send username and password from a website login form to a server.
If I just send the username and password without hashing them to an https server how exposed is the password I send in a POST request to somebody sniffing the package and finding out the password? The server is https enabled.
What would be the proper methodology to do this?
If the server is HTTPS enabled then any data going over the wire will be encrypted. It would be extraordinarily difficult for a network-only attacker to sniff even a plaintext password over HTTPS without one of the parties noticing.
HTTPS uses SSL/TLS on the transport layer, which is designed to provide both encryption and authentication. The SSL/TLS protocol, as part of its handshake, negotiates a symmetric encryption key that is different for each session and is used with a strong algorithm to protect data on the wire.
To mitigate 'man-in-the-middle' attacks, the asymmetric keys used by the client and server to establish a shared encryption key are also cryptographically signed by a certificate authority, both to provide assurance of trust and to prevent modification of the certificate. As long as the certificate authority can be trusted, it is easy to check the signature and and server name on the certificate itself. All modern browsers do this automatically and throw a warning to the user if there is any problem with the certificate.
As long as you and your users are aware of the issues surrounding the proper use of SSL (e.g. keep your private key safe, and make sure your users pay attention to browser warning), it's fine to send plaintext passwords over an SSL connection.
If the demands of your application are such that you cannot do even that, you might consider X.509 authentication (which uses certificates on the client side as well as the server side) or Kerberos authentication (which sends no passwords over the wire). For a basic web application, though, both of these solutions are overkill.

Resources