views:

147

answers:

5

How can I improve this username/password checking?

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Login(FormCollection collection)
    {
        var users =
            (from p in _dataContext.Users
            where p.Name == collection["Username"] && p.Password == collection["Password"]
             select p);

        if (users.Count() > 0)
        {
            // Login Succeed
            // To get the username I should do something like users.First().Name
            // and that's really bad...

            return RedirectToAction("Login");
        }
        else
        {
            // Login Faild
            return View();
        }
    }
+9  A: 

Have you considered Microsoft's Membership API? It handles all the details of usernames and passwords for you, and in a secure manner. Also, it looks like you plan on storing passwords in the clear, which is a cardinal sin in the realm of cryptography.

Bob Kaufman
A: 

Assuming your 'Username' field is guaranteed to be unique (i.e. a primary key), just select the user and compare the password field.

Also, you shouldn't generally store the original password in your DB. Instead, shore an MD5 hash or something (using the username as a salt, perhaps). Then compare the hash of the user input to the value in the DB rather than comparing the original value.

jheddings
MD5 is has some weaknesses and its use is not recommended anymore. I would recommend SHA1 or SHA2.
Martinho Fernandes
+1  A: 

I assume there can be only one result from that query. If so, you should use SingleOrDefault:

var user = _dataContext.Users.SingleOrDefault(p =>
                  p.Name == collection["Username"]
                  && p.Password == collection["Password"]);

if(user != null)
{
    // Go on...
    return RedirectToAction("Login");
}
else
{
    // Login Faild
    return View();

}

As others pointed out, there are other problems you should address in that code (namely, not storing plain-text passwords but hashes).

Martinho Fernandes
I wasn't really expecting this to be the accepted answer. Don't forget to do the hash thing. With salt. You really should.
Martinho Fernandes
@Martinho - makes sense to me. A lot of people hear "Membership API" and think "oh no, another unwieldy framework". I know I did the first time I saw it. It was only when an existing application forced me to work with it did I come to realize its merit. You answered the question as posed by @Alon.
Bob Kaufman
+1  A: 
  1. Use the asp.net membership model, don't reinvent the wheel.
  2. If you really want to reinvent the wheel, you need salting, and hashed passwords. Only store the hash of the password + salt. This is bare minumum.
chris.w.mclean
A: 

Like most people have mentioned, either use the Membership API that is already provided or encrypt the passwords in some secure way. Also, if you decide not to go that route and opt to encrypt passwords, make sure you use an established encryption library that you know works.

Reinventing encryption algorithms can be dangerously flawed (not to mention a waste of time since no value will be added) if they aren't done right. If passwords get leaked, it's not only your site that someone could exploit but potentially many other sites since people tend to use the same username and passwords.

Lastly, use aspnet_regsql.exe at the .Net Command line to configure a database with the schema for the Membership API. It literally takes less than 5 minutes to configure the database and switch your web.config.

Bit Destroyer
It is also not a good idea to store passwords with two-way cryptography. One-way algorithms (hashing) are much safer.
Martinho Fernandes
Yes. As a general rule, if you don't need to know the value, hash it.
Bit Destroyer