4
\$\begingroup\$

My team has developed an API and I've been tasked with creating an authentication layer that allows partners' applications to consume it. To that end, I've created a data store which houses an Application ID, Login and salted/hashed Password for that application to authenticate against. I want to hand back a Token for them to use (which is a key for session information that is kept on the server). The process to generate the Token is below. I have another process which reverses this to validate its authenticity. It seems to stand up to testing, but I'd like to know if there's anything else that should be done to make this properly secure.

private const string Password = "nottheactualpasswordthatisused..";

private static readonly byte[] _Salt =
{
    0x00, 0x01, 0x02, 0x03,
    0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0a, 0x0b,
    0x0c, 0x0d, 0x0e, 0x0f
};

private static async Task<string> CreateSecureSessionTokenAsync(int applicationId, DateTime createDate)
{
    using (var aes = Aes.Create())
    {
        if (aes == null)
        {
            return null;
        }

        using (var deriveBytes = new Rfc2898DeriveBytes(Password, _Salt))
        {
            aes.Key = deriveBytes.GetBytes(32);
            aes.IV = deriveBytes.GetBytes(16);
        }

        using (var encryptor = aes.CreateEncryptor())
        using (var memoryStream = new MemoryStream())
        {
            using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
            using (var writer = new StreamWriter(cryptoStream))
            {
                await writer.WriteLineAsync(Convert.ToString(applicationId)).ConfigureAwait(false);
                await writer.WriteLineAsync(Convert.ToString(createDate, CultureInfo.InvariantCulture))
                    .ConfigureAwait(false);
            }

            return Convert.ToBase64String(memoryStream.ToArray());
        }
    }
}
\$\endgroup\$
  • 2
    \$\begingroup\$ The salt shouldn't be hardcoded. Nor should the password. \$\endgroup\$ – Der Kommissar Apr 12 '16 at 17:53
  • \$\begingroup\$ Excellent. From a data store then? \$\endgroup\$ – Jesse C. Slicer Apr 12 '16 at 17:55
  • \$\begingroup\$ It is pretty common to create an hmac instead. Have you considered that? \$\endgroup\$ – Mattias Åslund Apr 12 '16 at 19:13
  • \$\begingroup\$ I have written what you see and am open to considering anything and everything that benefit it. \$\endgroup\$ – Jesse C. Slicer Apr 12 '16 at 19:18
  • 2
    \$\begingroup\$ Is it necessary to store information in the token? You could derive a random string, put it in a table and associate it with that client. When when a request is made you can look the token up against that table. \$\endgroup\$ – Sam Apr 13 '16 at 5:24
2
\$\begingroup\$

Using a string for storing a password is considered insecure because there is no possibility to delete that string from memory. From the SecureString documentation

An instance of the System.String class is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created, and it is not possible to predict when the instance will be deleted from computer memory. Because System.String instances are immutable, operations that appear to modify an existing instance actually create a copy of it to manipulate. Consequently, if a String object contains sensitive information such as a password, credit card number, or personal data, there is a risk the information could be revealed after it is used because your application cannot delete the data from computer memory.

so it would be better to use a SecureString but unfortunately that isn't an option when using Aes because it doesn't take an SecureString as a parameter. So what other options are there ? Just take a char[] and overwrite its content when the class is disposed.

The CreateSecureSessionTokenAsync() method should ideally return the token along with a random generated salt (maybe as tuple) to be stored in the data store to decrypt it later without the need that the customer will get the salt together with the token.

An implementation of a random salt using a parameterized length can be found in my answer here.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.