رمزنگاری پسورد با استفاده از Salt Hashing در ASP.Net MVC

Salt Hashing

مثالی که در این مقاله بررسی می شود، یک صفحه ثبت نام ساده است که پسورد کاربر را با استفاده از Salt Hashing  رمزنگاری می کند.

در رمزنگاری، Salt به صورت تصادفی برای هر پسورد تولید می شود.

در تنظیمات رایج آن، salt و پسورد به هم متصل (concatenate) می شوند و با استفاده از تابع hash پردازش می شوند، و نتیجه خروجی (نه پسورد اصلی) به همراه salt در دیتابیس ذخیره می شود.

رمزنگاری پسورد با استفاده از Salt Hashing

hash کردن اطلاعات امکان احراز هویت در مراحل بعدی را در اختیار ما قرار می دهد در حالی که نگه داری متن ساده پسورد در رویدادی داده های احراز هویت را ذخیره می کند، امن نمی باشد.

در این جا مثال ثبت نامی را نشان می دهیم که پسورد به صورت رمزشده در دیتابیس ذخیره می شود و زمانی که لاگین انجام می شود، پسورد رمزگشایی شده و کاربر لاگین می کند.

همچنین در این سیستم رمزنگاری یک Salt تصادفی تولید خواهیم کرد که این پسورد در زمان ذخیره در دیتابیس با این رمزنگاری، متفاوت خواهد بود.

در اینجا از روش Entity Framework code-first و همچنین ASP.Net MVC4 استفاده می کنیم.

گام ۱: ایجاد دیتابیس با استفاده از روش code first

یک پروژه Empty از MVC ایجاد می کنیم و یک پروژه دیگر از نوع class library زیرشاخه C# ایجاد می کنیم.

در این جا کلاسی با فیلدهای زیر ایجاد کردیم:


 public class User  {  
    [Key]  
    public int RegistrationId  
    {  
        get;  
        set;  
    } //This will be primary key column with auto increment  
    public string FirstName  
    {  
        get;  
        set;  
    }  
    public string LastName  
    {  
        get;  
        set;  
    }  
    public string UserName  
    {  
        get;  
        set;  
    }  
    public string EmailId  
    {  
        get;  
        set;  
    }  
    public string Password  
    {  
        get;  
        set;  
    }  
    public string Gender  
    {  
        get;  
        set;  
    }  
    public string VCode  
    {  
        get;  
        set;  
    }  
    public DateTime CreateDate  
    {  
        get;  
        set;  
    }  
    public DateTime ModifyDate  
    {  
        get;  
        set;  
    }  
    public bool Status  
    {  
        get;  
        set;  
    }  
} 

یک کلاس context به صورت زیر ایجاد می کنیم. قبل از ایجاد این کلاس ابتدا Entity Framework را از طریق Nuget Packages نصب می کنیم.


public class CmsDbContext : DbContext  
{  
    public DbSetlt;User ObjRegisterUser { get; set; } // Here User is the class

گام ۲: ایجاد کلاس Helper

در این جا به جای اضافه کردن متدها به Controller ها از کلاس Helper استفاده می کنیم:



public static class Helper  
{  
    public static string ToAbsoluteUrl(this string relativeUrl) //Use absolute URL instead of adding phycal path for CSS, JS and Images     
    {  
        if (string.IsNullOrEmpty(relativeUrl)) return relativeUrl;  
        if (HttpContext.Current == null) return relativeUrl;  
        if (relativeUrl.StartsWith("/")) relativeUrl = relativeUrl.Insert(0, "~");  
        if (!relativeUrl.StartsWith("~/")) relativeUrl = relativeUrl.Insert(0, "~/");  
        var url = HttpContext.Current.Request.Url;  
        var port = url.Port != 80 ? (":" + url.Port) : String.Empty;  
        return String.Format("{0}://{1}{2}{3}", url.Scheme, url.Host, port, VirtualPathUtility.ToAbsolute(relativeUrl));  
    }  
    public static string GeneratePassword(int length) //length of salt    
    {  
        const string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";  
        var randNum = new Random();  
        var chars = new char[length];  
        var allowedCharCount = allowedChars.Length;  
        for (var i = 0; i = length - 1; i++)  
        {  
            chars[i] = allowedChars[Convert.ToInt32((allowedChars.Length) * randNum.NextDouble())];  
        }  
        return new string(chars);  
    }  
    public static string EncodePassword(string pass, string salt) //encrypt password    
    {  
        byte[] bytes = Encoding.Unicode.GetBytes(pass);  
        byte[] src = Encoding.Unicode.GetBytes(salt);  
        byte[] dst = new byte[src.Length + bytes.Length];  
        System.Buffer.BlockCopy(src, 0, dst, 0, src.Length);  
        System.Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);  
        HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");  
        byte[] inArray = algorithm.ComputeHash(dst);  
        //return Convert.ToBase64String(inArray);    
        return EncodePasswordMd5(Convert.ToBase64String(inArray));  
    }  
    public static string EncodePasswordMd5(string pass) //Encrypt using MD5    
    {  
        Byte[] originalBytes;  
        Byte[] encodedBytes;  
        MD5 md5;  
        //Instantiate MD5CryptoServiceProvider, get bytes for original password and compute hash (encoded password)    
        md5 = new MD5CryptoServiceProvider();  
        originalBytes = ASCIIEncoding.Default.GetBytes(pass);  
        encodedBytes = md5.ComputeHash(originalBytes);  
        //Convert encoded bytes back to a 'readable' string    
        return BitConverter.ToString(encodedBytes);  
    }  
    public static string base64Encode(string sData) // Encode    
    {  
        try  
        {  
            byte[] encData_byte = new byte[sData.Length];  
            encData_byte = System.Text.Encoding.UTF8.GetBytes(sData);  
            string encodedData = Convert.ToBase64String(encData_byte);  
            return encodedData;  
        }  
        catch (Exception ex)  
        {  
            throw new Exception("Error in base64Encode" + ex.Message);  
        }  
    }  
    public static string base64Decode(string sData) //Decode    
    {  
        try  
        {  
            var encoder = new System.Text.UTF8Encoding();  
            System.Text.Decoder utf8Decode = encoder.GetDecoder();  
            byte[] todecodeByte = Convert.FromBase64String(sData);  
            int charCount = utf8Decode.GetCharCount(todecodeByte, 0, todecodeByte.Length);  
            char[] decodedChar = new char[charCount];  
            utf8Decode.GetChars(todecodeByte, 0, todecodeByte.Length, decodedChar, 0);  
            string result = new String(decodedChar);  
            return result;  
        }  
        catch (Exception ex)  
        {  
            throw new Exception("Error in base64Decode" + ex.Message);  
        }  
    }  
}  

گام ۳: تغییر فایل Web.Config

public class CmsDbContext : DbContext
{ 

public DbSetlt;User ObjegisterUser { get; set; } // Here User is the class
}

توجه داشته باشید که name در این جا همان نامی است که در کلاس context استفاده کردیم، به طور مثال: CmsDbContext.

پس از آن دیتابیسی با نام WebCMS و جدولی به عنوان user با ستون هایی به عنوان پارامترهای هر کلاس ایجاد خواهد شد و سپس عملیات Insert/Update/Delete را انجام می دهیم.

گام ۴: طراحی صفحه ثبت نام

	

<div class="panel panel-default mb0">
  
	    

<div class="panel-heading ui-draggable-handle">
  
	        

<h3 class="panel-title"><strong>New User </strong>  Registration</h3>

</div>


 @using (Html.BeginForm("Registration", "Admin", null, FormMethod.Post)) { @Html.AntiForgeryToken()  
	    

<div class="panel-body">
  
	        

<div class="form-group pt20">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">First Name</label>  
	            

<div class="col-md-6 col-xs-12">
  
	                

<div class="input-group"> <span class="input-group-addon"><span class="fa fa-pencil"></span></span>  
	                    <input type="text" class="form-control form-group" required="" name="FirstName"> @*Getting value by name and the name should be the name given in database column*@ </div>


 <span class="help-block">First Name field sample</span> </div>


            

<div class="clearfix"></div>


  
	        </div>

        

<div class="form-group">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">Last Name</label>  
	            

<div class="col-md-6 col-xs-12">
                

<div class="input-group"> <span class="input-group-addon"><span class="fa fa-pencil"></span></span>  
	                    <input type="text" class="form-control form-group" required="" name="LastName"> @*Getting value by name and the name should be the name given in database column*@ </div>


 <span class="help-block">Last Name field sample</span> </div>


            

<div class="clearfix"></div>


  
	        </div>


        

<div class="form-group">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">User Name</label>  
	            

<div class="col-md-6 col-xs-12">
  
	                

<div class="input-group"> <span class="input-group-addon"><span class="fa fa-pencil"></span></span>  
	                    <input type="text" class="form-control form-group" required="" name="UserName"> @*Getting value by name and the name should be the name given in database column*@ </div>


 <span class="help-block">User Name field sample</span> </div>


       

<div class="clearfix"></div>


  
	        </div>


        

<div class="form-group">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">Email Id</label>  
	            

<div class="col-md-6 col-xs-12">
  
	                

<div class="input-group"> <span class="input-group-addon"><span class="fa fa-pencil"></span></span>  
	                    <input type="text" class="form-control form-group" required="" name="EmailId"> @*Getting value by name and the name should be the name given in database column*@ </div>


 <span class="help-block">Email-Id field sample</span> </div>


	            

<div class="clearfix"></div>


  
	        </div>


        

<div class="form-group">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">Password</label>  
	            

<div class="col-md-6 col-xs-12">
  
	                

<div class="input-group"> <span class="input-group-addon"><span class="fa fa-unlock-alt"></span></span>  
	                    <input type="password" class="form-control" required="" name="Password"> </div>


 <span class="help-block">Password field sample</span> </div>


  
	            

<div class="clearfix"></div>


  
	        </div>

        

<div class="form-group">
  
	            <label class="col-md-3 col-xs-12 control-label align-right pt7">Gender</label>  
	            

<div class="col-md-6 col-xs-12">  
	                <label class="radio-inline">  
	                    <input type="radio" checked="checked" value="Male" name="Gender">Male</label>  
	                <label class="radio-inline">  
	                    <input type="radio" value="Female" name="Gender">Female</label>  
	            </div>

	            

<div class="clearfix"></div>


  
	        </div>


  
	    </div>


	    

<div class="panel-footer">  
	        <input type="reset" value="Clear Form" name="btnReset" class="btn btn-default" />  
	        <input type="submit" id="btnSubmit" name="btnSubmit" value="Submit" class="btn btn-primary pull-right" /> </div>


 }   
	 </div>

Controller ای با نام Admin برای ثبت نام اضافه کرده و کد زیر را در آن می نویسیم:


	public ActionResult Registration()  
	{  
	    return View();  
	}  
	[ValidateAntiForgeryToken]  
	[HttpPost]  
	public ActionResult Registration(User objNewUser)  
	{  
	    try  
	    {  
	        using(var context = new CmsDbContext())  
	        {  
	            var chkUser = (from s in context.ObjRegisterUser where s.UserName == objNewUser.UserName || s.EmailId == objNewUser.EmailId select s).FirstOrDefault();  
	            if (chkUser == null)  
	            {  
	                var keyNew = Helper.GeneratePassword(10);  
	                var password = Helper.EncodePassword(objNewUser.Password, keyNew);  
	                objNewUser.Password = password;  
	                objNewUser.CreateDate = DateTime.Now;  
	                objNewUser.ModifyDate = DateTime.Now;  
	                objNewUser.VCode = keyNew;  
	                context.ObjRegisterUser.Add(objNewUser);  
	                context.SaveChanges();  
	                ModelState.Clear();  
	                return RedirectToAction("LogIn", "Login");  
	            }  
	            ViewBag.ErrorMessage = "User Allredy Exixts!!!!!!!!!!";  
	            return View();  
	        }  
	    }  
	    catch (Exception e)  
	    {  
	        ViewBag.ErrorMessage = "Some exception occured" + e;  
	        return View();  
	    }  
	}

پس از آن، صفحه ثبت نام به شکل زیر خواهد بود:

پس از آن می توانید دیتابیس خود را چک کرده و ستون پسورد را مشاهده نمایید. همچنین پسوردی وارد کرده و پس از آن متوجه خواهید شد که پسورد متفاوتی در دیتابیس خواهید یافت.

گام ۵: طراحی صفحه لاگین

	

<div class="form-horizontal">
 @using (Html.BeginForm("LogIn", "Login", null, FormMethod.Post)) { @Html.AntiForgeryToken()  
	    

<div class="form-group">
  
	        

<div class="col-md-12">  
	            <input type="text" class="form-control" required="" placeholder="E-mail" name="UserName" /> </div>


  
	    </div>


  
	    

<div class="form-group">
  
	        

<div class="col-md-12">  
	            <input type="password" class="form-control" required="" placeholder="Password" name="Password" /> </div>


  
	    </div>


  
	    

<div class="form-group">
  
	        

<div class="col-md-6"> <a href="#" class="btn btn-link btn-block">Forgot your password?</a> </div>


  
	        

<div class="col-md-6">  
	            <button class="btn btn-info btn-block">Log In</button>  
	        </div>


  
	    </div>


  
	    

<div class="login-subtitle"> Don't have an account yet?@Html.ActionLink("Create an account", "Registration", "Admin") </div>


 }   
	 </div>

یک Controller با نام Login برای انجام لاگین به صورت زیر اضافه می کنیم:


div class="form-horizontal"> @using (Html.BeginForm("LogIn", "Login", null, FormMethod.Post)) { @Html.AntiForgeryToken()  
	    

<div class="form-group">
  
	        

<div class="col-md-12">  
	            <input type="text" class="form-control" required="" placeholder="E-mail" name="UserName" /> </div>


  
	    </div>


  
	    

<div class="form-group">
  
	        

<div class="col-md-12">  
	            <input type="password" class="form-control" required="" placeholder="Password" name="Password" /> </div>


  
	    </div>


  
	    

<div class="form-group">
  
	        

<div class="col-md-6"> <a href="#" class="btn btn-link btn-block">Forgot your password?</a> </div>


  
	        

<div class="col-md-6">  
	            <button class="btn btn-info btn-block">Log In</button>  
	        </div>


  
	    </div>


  
	    

<div class="login-subtitle"> Don't have an account yet?@Html.ActionLink("Create an account", "Registration", "Admin") </div>


 }   
	 </div>


  

یک Controller با نام Login برای انجام لاگین به صورت زیر اضافه می کنیم:

	public ActionResult Login()  
	{  
	    return View();  
	}  
	[ValidateAntiForgeryToken]  
	[HttpPost]  
	public ActionResult LogIn(string userName, string password)  
	{  
	    try  
	    {  
	        using(var context = new CmsDbContext())  
	        {  
	            var getUser = (from s in context.ObjRegisterUser where s.UserName == userName || s.EmailId == userName select s).FirstOrDefault();  
	            if (getUser != null)  
	            {  
	                var hashCode = getUser.VCode;  
	                //Password Hasing Process Call Helper Class Method    
	                var encodingPasswordString = Helper.EncodePassword(password, hashCode);  
	                //Check Login Detail User Name Or Password    
	                var query = (from s in context.ObjRegisterUser where(s.UserName == userName || s.EmailId == userName) && s.Password.Equals(encodingPasswordString) select s).FirstOrDefault();  
	                if (query != null)  
	                {  
	                    //RedirectToAction("Details/" + id.ToString(), "FullTimeEmployees");    
	                    //return View("../Admin/Registration"); url not change in browser    
	                    return RedirectToAction("Index", "Admin");  
	                }  
	                ViewBag.ErrorMessage = "Invallid User Name or Password";  
	                return View();  
	            }  
	            ViewBag.ErrorMessage = "Invallid User Name or Password";  
	            return View();  
	        }  
	    }  
	    catch (Exception e)  
	    {  
	        ViewBag.ErrorMessage = " Error!!! contact cms@info.in";  
	        return View();  
	    }  
	}  

پس از آن صفحه لاگین را به صورت زیر مشاهده خواهید کرد:

نام کاربری و پسورد مناسب وارد نموده و لاگین نمایید.

  • پسورد: www.mspsoft.com
فاطمه زکایی

فاطمه زکایی هستم. فارغ التحصیل کارشناسی مهندسی نرم افزار، مدت سه سال هست که در زمینه توسعه اپلیکیشن های تحت وب و اندروید و همچنین تولید محتوای تخصصی برنامه نویسی تحت وب و اندروید در مجموعه mspsoft در خدمت شما هستم.

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

    shervin پاسخ

    سلام ممنون از مقاله خوبتون
    من به یه مشکل در حین ارتباط با پایگاه برخوردم ممنون میشم راهنمایی کنید.
    سپاس
    ارور"Cannot open database "WebCMS" requested by the login. The login failed.
    Login failed for user 'salimian\sa'."

      مسعود شریفی پور پاسخ

      ارتباط با دیتابیس فراهم نیست.