Search code examples
sqlasp.net-mvcdatabasepassword-protection

How to hash and add salt to password from csv C#


I am a student totally new to C# programming. I am currently doing a mini security project using MVC. The project: Allow users to upload a csv file containing accounts but password not hash and salt. (Done) Then I will send the file to virustotal and scan it before saving to the server (Done) After saving, I need to insert the data in the csv file and hash and salt the password into the database. (Need help)

My Controller

public ActionResult Upload(HttpPostedFileBase file)
    {
        if (System.IO.Path.GetExtension(file.FileName).Equals(".csv"))
        {
            //{0} = Y, {1} = M, {2} = D, {3} = H, {4} = min, {5} = Sec
            string datetime = string.Format("{0}{1}{2}-{3}{4}{5}", DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
            string fileName = string.Format("{0}_{1}.csv", file.FileName.Substring(0, (file.FileName.Length - 4)), datetime);
            var fileStream = new System.IO.MemoryStream();
            file.InputStream.CopyTo(fileStream);

            var vtObj = new VirusTotal("%API KEY%");
            vtObj.UseTLS = true;
            try
            {
                var fileResults = vtObj.ScanFile(fileStream, fileName);
                var report = vtObj.GetFileReport(fileResults.ScanId);

                int resPos = report.Positives;

                if (resPos == 0)
                {
                    string savePath = Server.MapPath("~/CSV/" + fileName);
                    file.SaveAs(savePath);
                    try
                    {
                        //removing the first row
                        insertDB(fileName, savePath);
                        ViewBag.error = "Updated successfully";
                        return View();

                    }
                    catch (Exception ex)
                    {
                        ViewBag.error = "Unable to update DB" + ex;
                        return View("Index");
                    }
                }
                else
                {
                    ViewBag.error = "Unable to upload";
                    return View("Index");
                }
            }
            catch (Exception ex)
            {
                ViewBag.error = string.Format("Unable to upload | One min only can upload 4 times | {0} | {1}", ex, fileName);
                return View("Index");
            }
        }
        else
        {
            ViewBag.error = "Unable to upload";
            return View("Index");
        }
    }

    public void insertDB(string fileName, string savePath)
    {

        using (DB01Entities dbc = new DB01Entities())
        {
            string sql = string.Format(@"CREATE TABLE [dbo].[TempImport]
                                        (
                                            Name varchar(255),
                                            Password VARBINARY(50)
                                        )

                                        bulk insert [dbo].[TempImport] from '%MyPATH%\CSV\{0}' with (ROWTERMINATOR = '\n')

                                        INSERT INTO dbo.Employee
                                        (
                                            Name
                                            Password
                                        )
                                        SELECT  name
                                        FROM       dbo.TempImport

                                        DROP TABLE dbo.TempImport", fileName);
            dbc.Database.ExecuteSqlCommand(sql);
            dbc.SaveChanges();
        }
    }
}
}

My Index

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

@using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="File" id="file" accept=".csv"/>
<input type="submit" value="Upload" />
<div class="error">@ViewBag.error</div>
}

Upload

@{
ViewBag.Title = "Upload";
}

<div class="success">@ViewBag.error</div>
<a href="/Home/Index">Back to Index>></a>

Solution

  • Assuming a bulk insert via SQL is not a requirement:

    Since you're using ASP.NET, use the Crypto class to hash your passwords:

    var hashedPassword = Crypto.HashPassword(plainTextPassword);
    

    When you want to verify the plain text version later, use

    bool matches = Crypto.VerifyHashedPassword(hashedPassword, plainTextPassword);
    

    The hashed password contains the salt used when hashing, and Crypto knows how to extract the salt from the password hash.

    Since you have a stream to read from:

    using(var reader = new StreamReader(fileStream))
    {
        using (DB01Entities dbc = new DB01Entities())
        {
            while(reader.Peek != -1)
            {
                var parts = reader.ReadLine().Split(',');
                var hashedPassword = Crypto.HashPassword(parts[1]);
                dbc.Employees.Add(new Employee { Name = parts[0], Password = hashedPassword });
            }
    
            dbc.SaveChanges();
        }
    }
    

    This also has the advantage of not requiring the file to be saved anywhere, as you can just use the bytes you already have in memory.