Link to home
Start Free TrialLog in
Avatar of Brian
BrianFlag for United States of America

asked on

Forgot your password help

Hello Experts,

I have an application that I need to give users the ability to reset their password. So far I have a process that works half way. Please see what I have below along with code. My question(s) is I need help with encrypting/decrypting the usersid when they recieve an email. I don't want the user to be able to reset anyone elses password by guessing another usersid.

Step 1: User needs to enter his/her username and email address. If correct an email will be sent with a link to the user.

Step 2: User recieves link and will need to click on the link and they will be prompted to enter a new password. This is the step that I'm having trouble with. I would like the usersid to be encrypted in the email. When the user clicks on the link I would like to be able to retrievce his/her userid and store it in a HiddenField and have it decrypted at that point. Then user can enter new password to have it reset.

Also, please note that when I enter the actual usersid into the querystring it does not retrieve the users information.

Forgot Password CodeBehind:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Net.Mail;
using System.Net.NetworkInformation;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;

public partial class application_forgotpassword : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        lblForgotPasswordError.Visible = false;
    }

    protected void SendForgotPasswordEmail()
    {
        SmtpClient smtpClient = new SmtpClient();
        MailMessage message = new MailMessage();

        MailAddress fromAddress = new MailAddress("no-reply@domain.org", "Reporting System");
        MailAddress toAddress = new MailAddress(HttpUtility.HtmlEncode(txtWorkEmail.Text));

        message.From = fromAddress;
        message.To.Add(toAddress);

        string EMPURL = "<span style=\"font-size: 14px; color: #0c9b19; font-family: Arial\"><font face='arial' color='#666666'>" + "Click <a href='http://application/resetpassword.aspx?emp_id=" + hf_emp_id.Value + "'>here </a>to reset your password.";

        message.Subject = "Reset your Password";
        message.IsBodyHtml = true;
        message.Body = "<html><head><title>" + "</title></head><body>" + "<p>" + "<span style=\"font-size: 16px; color: #0c9b19; font-family: Arial\"><b>Forgot your password?</b><font face='arial' color='#666666'>" + "<br /><br />" + EMPURL + "<span style=\"font-size: 12px; font-style: italic; color: #de1919; font-family: Arial\"><br />" + "<span style=\"font-size: 14px; font-style: italic; color: #de1919; font-family: Arial\"><br /><br />" + "** Passwords are secure. Please make sure that you remember your password or store it in a safe place. **" + "</body></html>";

        smtpClient.Host = "mail.domain.org";
        smtpClient.Send(message);
    }

    protected void btn_forgotpassword_Click(object sender, EventArgs e)
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessTracker"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "RetrieveForgottenPassword";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            cmd.Parameters.Add("@emp_username", SqlDbType.VarChar, 50).Value = txtUserName.Text;
            cmd.Parameters.Add("@emp_email", SqlDbType.VarChar, 100).Value = txtWorkEmail.Text;

            try
            {
                conn.Open();

                SqlDataReader rdr = cmd.ExecuteReader();

                if (rdr.Read())
                {
                    hf_emp_id.Value = EncryptDecryptQueryString.EncodeTo64(rdr["emp_id"].ToString());

                    SendForgotPasswordEmail();
                    Response.Redirect("forgotpasswordsuccess.aspx");
                }
                else
                {
                    lblForgotPasswordError.Text = "We are unable to locate your account.";
                }
            }

            catch (Exception ex)
            {
                lblForgotPasswordError.Text = ex.Message.ToString();
            }
        }
    }
}

Open in new window


EncryptDecryptQueryString Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Security.Cryptography;

/// <summary>
/// Summary description for EncryptDecryptQueryString
/// </summary>
public class EncryptDecryptQueryString
{
    public static string EncodeTo64(string toEncode)
    {
        byte[] toEncodeAsBytes = System.Text.Encoding.Unicode.GetBytes(toEncode);
        string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

        return returnValue;
    }

    /// <summary>
    /// The method to Decode your Base64 strings.
    /// </summary>
    /// <param name="encodedData">The String containing the characters to decode.</param>
    /// <returns>A String containing the results of decoding the specified sequence of bytes.</returns>
    public static string DecodeFrom64(string encodedData)
    {
        byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
        string returnValue = System.Text.Encoding.Unicode.GetString(encodedDataAsBytes);

        return returnValue;
    } 
}

Open in new window


RetrieveForgottenPassword Stored Procedure:


ALTER PROCEDURE [dbo].[RetrieveForgottenPassword]

(
@emp_username varchar(50),
@emp_email varchar(100)
)

AS 

SELECT emp_id, emp_username, emp_email
FROM Employees
WHERE emp_username = @emp_username AND emp_email = @emp_email

Open in new window


Reset Password CodeBehind:

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Net.Mail;
using System.Net.NetworkInformation;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Cryptography;

public partial class application_resetpassword : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        RetrieveEmployeeIDFullName();
        lblResetPasswordError.Visible = false;
    }

    protected void RetrieveEmployeeIDFullName()
    {
        string empid = EncryptDecryptQueryString.DecodeFrom64(Request.QueryString["emp_id"].ToString());

        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessTracker"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "RetrieveEmployeeFirstLastName";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            cmd.Parameters.Add("@emp_id", SqlDbType.Int).Value = empid;

            try
            {
                conn.Open();

                SqlDataReader rdr = cmd.ExecuteReader();

                if (rdr.Read())
                {
                    hf_emp_id.Value = rdr["emp_id"].ToString();
                    lblUsersFullName.Text = rdr["emp_firstname"].ToString();
                }
            }

            catch (Exception ex)
            {
                ex.Message.ToString();
            }
        }
    }

    protected void btn_ResetPassword_Click(object sender, EventArgs e)
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessTracker"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "UpdateEmployeesPassword";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            cmd.Parameters.Add("@emp_id", SqlDbType.Int).Value = hf_emp_id.Value;
            cmd.Parameters.Add("@emp_password", SqlDbType.Binary, 96).Value = PasswordHash.HashPassword(txtPassword.Text);

            try
            {
                conn.Open();
                cmd.ExecuteNonQuery();

                Response.Redirect("resetpassword.aspx");
            }

            catch (Exception ex)
            {
                lblResetPasswordError.Text = ex.Message.ToString();
            }
        }
    }
}

Open in new window


Reset Password Stored Procedures:

ALTER PROCEDURE [dbo].[RetrieveEmployeeFirstLastName]

(
@emp_id int
)

AS 

SELECT emp_id, emp_firstname, emp_lastname
FROM dbo.Employees
WHERE emp_id = @emp_id

Open in new window

Avatar of Rajar Ahmed
Rajar Ahmed
Flag of India image

As you explained so many things [i think its a complete process ]  its difficult to follow where your lost / having issue . Better tell, where we need to look at it ?
However, There is no need of hidden field assignment, just encrypt/decrypt assign it on varaible use it accordingly
    string  encUserId = yourEncrptLogic(username.text);
          string mailBody ="<a href="resetPage.aspx?ssid="+encUserId>Reset Password</a>";

Open in new window

   string decUserID = yourDecryptLogic(Request.QueryString["ssid"]);
            //pass this to update your password 

Open in new window

Meeran03
Avatar of Brian

ASKER

So I don't need to use a hiddenfield on either page of those pages or code?
Yes, As you can
  1.Retrieve username from textbox itself while encrypting.
  2.Retrieve username from querystring  itself while decrypting

So, there is no need of hidden field .
Avatar of Brian

ASKER

What did you think about the encryption/decryption that I'm using. Actually I think it only encodes/decodes.

Do you know of a more secure or better approach?
Avatar of Brian

ASKER

Thanks, which algorithim do you suggest for a more secure site?
ASKER CERTIFIED SOLUTION
Avatar of Rajar Ahmed
Rajar Ahmed
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Brian

ASKER

Hi meeran03,

Ok, what algorithim do you suggest is better for hashing? That is how I store my passwords now. I can upload the code I'm using to show you if  you like if you wouldn't mind looking at it.
hi asp_net2,

 what algorithim do you suggest is better for hashing?
  1. SHA256
   2. SHA1
 
  Using SALT on either of your hashing algorithm will give more security .

http://stackoverflow.com/questions/1756188/how-to-use-sha1-or-md5-in-cwhich-one-is-better-in-performance-and-security-fo 


I can upload the code..
   Yes,  i wouldnt mind if that was another thread lol . As it varies more than to  the original question asked .

Meeran03