Avoid transmitting plain text passwords

First I would like to spell out in bold capital letters that this nowhere as safe as SSL. It is prone to man-in the-middle attack such as session hijacking. Okay, that said, here is an easy way to avoid transmitting plain text passwords with basic authentication forms. The idea is that the server initially generates a salt for the session and sends it to the client. The client then provides a password that is SHA1-hashed with the salt client side, and only this hash is sent back to server. The server also computes the hash from a stored password and then matches the two. Thanks to Chris Veness for providing the Javascript SHA-1 implementation. Here goes the View:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <% using (Html.BeginForm()) { %> " /> <% } %> -- and the example MVC controller code:

using System; using System.Globalization; using System.Linq; using System.Web.Mvc; namespace MvcApplication1.Controllers { public class AccountController : Controller { public ActionResult LogOn() { byte[] salt; if ((salt = (byte[])Session["salt"]) == null) using (var sha1 = System.Security.Cryptography.SHA1Managed.Create()) { salt = new byte[64]; new Random().NextBytes(salt); Session["salt"] = sha1.ComputeHash(salt); } ViewData.Add("salt", ToHex((byte[])Session["salt"])); return View(); } static string ToHex(byte[] buf) { return buf.Aggregate(string.Empty, (a, b) => a += b.ToString("x2")); } static byte[] FromHex(string hex) { byte[] buf = new byte[hex.Length / 2]; for (int i = 0; i < buf.Length; i++) { string ch = string.Empty + hex[i * 2] + hex[i * 2 + 1]; buf[i] = byte.Parse(ch, NumberStyles.HexNumber); } return buf; } string GetStoredPassword() { return "test"; // read from somewhere safe } [AcceptVerbs(HttpVerbs.Post)] public ActionResult LogOn(string password) { byte[] providedPass = FromHex(password); byte[] actualPass = System.Text.Encoding.UTF8.GetBytes(GetStoredPassword()); using (var sha1 = System.Security.Cryptography.SHA1Managed.Create()) { byte[] salt = (byte[])Session["salt"]; byte[] actualHash = sha1.ComputeHash(actualPass); byte[] actualPassword = sha1.ComputeHash( System.Text.Encoding.UTF8.GetBytes( ToHex(salt.Concat(actualHash).ToArray()) ) ); if (ToHex(actualPassword) != password) { ViewData.Add("salt", ToHex(salt)); return View(); // Password refused } else { Session.Add("loggedin", DateTime.Now); return RedirectToAction("Index", "Home"); // Password accepted } } } } }

Google
m@kli.dk @klinkby RSS feed  GitHub