When you build a distributed system, one of important questions to answer is how secure your system should be. If your data is confidential, you need to secure it using encryption mechanisms. However there's one more thing that most developers ignore - attack on service availability. We all know about DoS (denial of service) attacks. They are possible with almost any kind of network service. One of important actions one can take is user authentication. User authentication lets you have certain control over people or systems that use resources of your server.
Almost any modern internet protocol supports some kind of user authentication. MsgConnect is not an exception. When you send a message with MsgConnect, you can optionally specify so-called Message Credentials (MCMessageCredentials). MCMessageCredentials is a structure that contains 2 16-byte fields. You can put whatever you want there (later we will review several methods of authentication using MessageCredentials). When the message is received by recipient, MCMessenger.OnValidateCredentials event is fired. The event handler is passed a message itself and contents of MCMessageCredentials structure. The application can check credentials and decide whether the message should be accepted or declined.
While the structure of MCMessageCredentials might seem not very flexible, yet several ways of secure authentication are possible.
1. General considerations.
First we need to define, what kind of authentication is possible in MsgConnect. MsgConnect is based on stateless operations. This means that one message should include everything necessary to process (or decline the request). There exist complex challenge-response authentication schemes; however on higher levels of MsgConnect operations (i.e. on message level) these schemes can't be employed. So we will deal with username/password authentication. Username/password doesn't mean that meaningful words should be used. Both username and password can contain any data of any size. The idea behind them is that existence of username is publicly known and the password is secret.
Next we review our options in validation of the password. There are two approaches:
- The server is secure enough to keep a database with username/password pairs (probably in encrypted form). Both username and password can be obtained in decrypted form.
- b) The server keeps usernames in decrypted mode and also the hashes of user passwords. The password can not be obtained in decrypted form.
If the server can obtain the password from it's database, then the client doesn't need to transfer the password over network. If the server keeps only hashes of user passwords, then the client should send the password to the server. Why is this so? When the client sends credentials (username/password), the server should compare the received credentials with credentials in it's user database. To do so the server should either obtain the original password from the database and compare it with what the client has sent, or encode (encrypt, hash) the received password and compare it with database contents.
Both approaches have certain drawbacks. If the server keeps passwords in the database and can get them in "regular" form, then the danger is that the hacker can obtain the database in some way and will be able to access the protected resources. If the server keeps only hashes (result of irreversible transformation), then the server needs to receive the password from the client, perform the same irreversible transformation and compare the hashes. The danger in second case is that the password is transferred over network and can be recovered by the hacker.
Most internet protocols employ second approach, i.e. the password is slightly encoded (not even encrypted) and sent to the server).
2. Simple schemes.
The easiest thing to do is to put username and password as plain text to MCMessageCredentials structure and send a message as is. The danger is obvious - these data are visible with any network capturing tool.
One can encode a password a bit. For example, in the following way:
MCMessageCredentials.Username (hexadecimal representation): 65 78 61 6D 70 6C 65 00 00 00 00 00 00 00 00 00 ("example")
MCMessageCredentials.Password (hexadecimal representation): 70 61 73 73 77 6F 72 64 00 00 00 00 00 00 00 00 ("password")
for (int i = 0; i < 16; i++)
password[i] = password[i] ^ username[i]; // xor each character of password with corresponding character of username
Encoded password: 15 19 12 1E 07 03 17 64 00 00 00 00 00 00 00 00
Such scheme lets the server decode the password back and perform all necessary comparisons.
Note that this is encoding, not encryption. Encoding is based on assumption that the attacker doesn't know the algorithm used to encode the data. It is cryptographically weak and the person who has basic knowledge of cryptanalysis will be able to decode the above sample in minutes. However to prevent clear-text transfer this scheme can be ok. It doesn't force the server to keep passwords in the database, i.e. the server can keep hashes.
3. Password hashing
One wide-spread techniques is transferring a hash of the password to the server. The server must have passwords in it's user database to be able to perform hashing too. The weak place is that the hash becomes a password transferred as a plain text. To avoid such situation (and prevent recovery of the password from it's hash) so-called salt is used. Salt is the value that is added to actual data before calculating the hash. Salt lets one completely change the resulting hash value. Using different salt with each operation effectively prevents recovery of the password from it's hash.
This is how it works:
- The client puts username to MCMessageCredentials.Username field
- The client generates a 32-bit salt. Note: do NOT use randomizer that is shipped with your development tool. Use a special cryptographically strong randomizer. Right now MsgConnect doesn't include one, but there are plans to add it in future.
- The client calculates a hash (using MD5 algorithm) of password+salt and puts the result to MCMessageCredentials.Password field
- The salt is put to Param2 field of MCMessage object (unfortunately there's no other place to put it unless your username is limited to 12 bytes or less).
- The server receives the message and performs the same operation as in step 3. Then the hash is compared to the one received from the client.
4. Encryption with shared secret
Another option can be to use some kind of encryption. Let's suppose that the server and the client share some kind of secret key. Then one can use symmetric encryption algorithm (such as AES) to encrypt the password with the shared secret key. The secret keys can be different for each client/server pair. This is how it works:
- The client encrypts the password with known secret key
- The username and encrypted password are put to MCMessageCredentials and sent to the server. The secret key is NOT sent anywhere
- The server searches the user database for a password (or password hash) and a secret key.
- The secret key is used to decrypt the received password and the decrypted password is compared with the one from the database. If necessary, hashing is applied to decrypted password.
Such scheme is quite secure because it prevents interception of the password via network capture mechanisms. If the secret key is compromised (lost or stolen by hacker), the server can easily change the secret key. If the server keeps password hashes instead of passwords themselves, then the weakest place is a secret key stored on the client - the users (or system administrator) should take care to prevent secret key from being stolen. One of the ways is to keep it on hardware token which doesn't give keys away. Such token can perform certain operations (such as encryption of the password with one of symmetric algorithms) using the private key. In this way the only way to steal the key is steal the token and this can be easily discovered and appropriate actions will be taken.
5. Challenge-response using messages
Take the scheme with password encryption using shared secret. The scheme is quite secure in that it doesn't let third parties discover the actual password. However let's review the following scenario: administrator logs into the remote server and sends the authenticated message with "Reboot" command. The attacker intercepts the message. The attacker doesn't need to discover the password. All he needs to do is to send the message again and again. This will effectively block the server. This is when simple one-step authentication is just not enough.
We need to employ challenge-response scheme. Such authentication consists of the following steps:
- The client sends authentication request to the server.
- The server sends a reply to the client, passing the client some unique and random ID. This can be even current time on the server.
- The client takes the given ID, password and uses the ID as a salt in "hashing" scheme. Alternatively, the ID is encrypted along with the password in "shared-secret" scheme.
- The message is sent to the server with encrypted information and command.
- The server receives the encrypted login information, decrypts it and checks the ID. If the ID was issued not long ago, then the authentication can continue. If the ID is invalid or expired, authentication fails.
- If the client needs to send more messages, it can use the ID for certain time, then it needs to request new ID again.
The idea behind such scheme is that if the attacker intercepts one message, it can't resend it later because the ID will expire. Note, that challenge-response should be used in conjunction with secure authentication schemes such as hashing and shared secret schemes.
There are many ways to implement secure user authentication. For example, we didn't discuss using asymmetric cryptography because it is, while being quite flexible and secure, hard to use with existing credentials method of MsgConnect and can't be implemented using only MsgConnect code. However when implementing authentication, you need to carefully evaluate all possible threats to your distributed system and see how certain authentication scheme can protect your system from various types of attacks. And involving a good consultant in security is always a wise step.