URL. Hash, Encrypt, ...

  • Thread starter Thread starter shapper
  • Start date Start date
S

shapper

Hello,

I am creating a mechanism for a user to recover a password. I know two
options:

1) Generate a new random password and send it to the user by email.
Maybe not the safest way to send a password.

2) Send a url to the user for a form to change the password.
The url contains the ID of the user and a KEY.
The Key is created from various fields in the USERS table:
Username + CreatedDate + Name

When the user uses the URL I check if the Key is valid.
If it is I allow the user to change the password in a form even if
not validated.

BUT: Shouldn't this URL expire somehow?
How can I do this?
Since the Key is hashed ... I am not able to place the
date there.

Maybe I should use another approach? Encrypt? To be able to
recover the DateTime from the Key?

I think option 2 is better than option 1 or not?

Thank You,
Miguel
 
Is this an ASP .NET application? If so, there is already a built-in
mechanism that supplies this behavior in the ASP .NET Membership & Roles
area.

-Scott
 
1 Generate a suitable large random number.

You mean considering that is a password?
For example with length equal to 8, which is the minimum length I
usually set to passwords ...
2 Encrypt this number with the user's public RSA key.

Doesn't the private key include the public key?

So I need to generate two keys, one private and one public and
save in the database?

Like so?

RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
byte[] privateAndPublicKeys = RSA.ExportCspBlob(true);
byte[] publicKey = RSA.ExportCspBlob(false);

The ExportCspBlob says for the parameter:
"true to include the private key"
This is why I am not sure how to separate both.
3 Send the encrypted number to the user in an e-mail.

Got it.
4 The new password is the SHA-256 hash of the random number (in
Base-64 if you want to make it typeable on a keyboard).

I don't get the typeable part ...

If I understood correctly I get the encrypted number use Base64 to
convert to String and send it to user by email.
And I also turn it to byte[] and hash it using SHA 256. I save the
hash and the salt in the database.
Then when the user inserts that number I convert it to byte[] using
UTF8 and verify it against the hash I have on the database.

Correct?
5 Expire the new password the first time it is used to force the user
to change to their own new password when they log back on.

I can create a column on the database Users table: Bool
TemporaryPassword.
When I send the password I set it to true. When the user logins I
redirect him to the password change form and set it to false.
I suppose a column on the table for this is necessary. Correct?
This requires all users to have their own RSA public/private keys.
They could perhaps be generated as part of the sign-up process.

Yes, no problem in doing that on the signup process.
And I can use the RSA keys for other things if needed correct?
As is usual with security, how valuable is what you are trying to
protect?  What is the cost to the business is the data is compromised?

Not a lot ... But the way I see it is if I am spending time learning
and implementing things then it would be better to do it the correct
way.

Thank You,
Miguel
 
Is this an ASP .NET application?  If so, there is already a built-in
mechanism that supplies this behavior in the ASP .NET Membership & Roles
area.

Yes, it is an ASP.NET application but I am not using the Membership,
Roles and Profile providers.

I still use FormsAuthentication but I created my own Membership/Roles/
Profile services.
It becomes more flexible to me able to use my own SQL tables and to
create custom behaviors like automatic unlocking and so on that I
wasn't able to do using the default providers.

But everything is still on FormsAuthentication ...
 
  You mean considering that is a password?
  For example with length equal to 8, which is the minimum length I
usually set to passwords ...

Here "large" means between 128 bits and at least 256 bits.  128 bits
is the basic minimum for security at the moment.


     Doesn't the private key include the public key?

No, they are separate.  They do have to be generated together.


     So I need to generate two keys, one private and one public and
save in the database?
    Like so?
     RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
     byte[] privateAndPublicKeys = RSA.ExportCspBlob(true);
     byte[] publicKey = RSA.ExportCspBlob(false);
     The ExportCspBlob says for the parameter:
     "true to include the private key"
     This is why I am not sure how to separate both.

I have never used RSA on .NET so I am not the best person to ask about
the specifics.  The documentation and the examples it contains will be
a better source than me.

The user will need to store their private key securely at their end to
enable them to decrypt their new password.  You do not need to store
the users private keys, just their public keys.


     Got it.
  I don't get the typeable part ...

A SHA-256 hash is an array of bytes, which cannot be directly typed on
a keyboard - values like 0x00 are not easy to enter through a
keyboard.  The Base-64 conversion only uses typeable characters: A..Z,
a..z, 0..9, +, /  It is very easy to type Base-64 on a keyboard.  A
raw hash tends to be used for computer-to-computer security and is
never seen directly by the user.


  If I understood correctly I get the encrypted number use Base64 to
convert to String and send it to user by email.

No.  Encrypt the number using RSA.  The user decrypts the number and
hashes it.  The hash function can use either the number itself (as a
byte array) or a string of ASCII digits.  It does not really matter as
long as both ends do the same.
  And I also turn it to byte[] and hash it using SHA 256. I save the
hash and the salt in the database.

At your end you need to perform the same process as the user to turn
the random number into a password.  Then you do the usual salting and
stretching we discussed in the other thread and store the salt and the
final hash.
  Then when the user inserts that number I convert it to byte[] using
UTF8 and verify it against the hash I have on the database.

The password will just be a character string and can be verified in
the same way as any other password.


  Correct?
   I can create a column on the database Users table: Bool
TemporaryPassword.
   When I send the password I set it to true. When the user logins I
redirect him to the password change form and set it to false.
   I suppose a column on the table for this is necessary. Correct?

I would be inclined to have an expiry date for every password so users
are forced to change their passwords regularly.  Just set the expiry
date to yesterday for a temporary password and let the system give the
user one login to set a new password as with any expired password.


Yes, no problem in doing that on the signup process.
And I can use the RSA keys for other things if needed correct?
Yes.

rossum
Not a lot ... But the way I see it is if I am spending time learning
and implementing things then it would be better to do it the correct
way.
Thank You,
Miguel

Thank You Rossum. This was really helpful ...

Thanks,
Miguel
 
Back
Top