2012-06-22 14 views
5

Im CS major y acabo de terminar de diseñar un sitio ASP.net, y para el sitio necesitaba un sistema de autenticación de inicio de sesión ... No quería utilizar SQLMembershipProvider porque realmente quería aprender cómo hacer uno solo ... De todos modos, esto es lo que se me ocurrió, y me preguntaba si alguien me puede dar algunos comentarios, sugerencias o consejos.Autenticación ASP.net

Gracias de antemano

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

/// <summary> 
/// Summary description for PwEncrypt 
/// </summary> 
public class PwEncrypt 
{ 
    public const int DefaultSaltSize = 5; 

    private static string CreateSalt() 
    { 
     RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
     byte[] buffer = new byte[DefaultSaltSize]; 
     rng.GetBytes(buffer); 
     return Convert.ToBase64String(buffer); 
    } 

    public static string CreateHash(string password, out string salt) 
    { 
     salt = CreateSalt(); 
     string saltAndPassword = String.Concat(password, salt); 
     string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1"); 
     hashedPassword = string.Concat(hashedPassword, salt); 
     return hashedPassword; 
    } 
     public static string CreateHashAndGetSalt(string password, string salt) 
    { 

     string saltAndPassword = String.Concat(password, salt); 
     string hashedPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPassword, "SHA1"); 
     hashedPassword = string.Concat(hashedPassword, salt); 
     return hashedPassword; 
    } 

    public static bool comparePassword(string insertedPassword, string incUserName, out string newEncryptedPassword, out string originalPassword) 
    { 
     databaseInteraction DBI = new databaseInteraction(); 
     string actualPassword =""; 
     string salt = ""; 


     DBI.getSaltandPassword(incUserName, out salt, out actualPassword); 
     string hashedIncPassword = PwEncrypt.CreateHashAndGetSalt(insertedPassword, salt); 
     // hashedIncPassword = string.Concat(hashedIncPassword, salt);  
     newEncryptedPassword = hashedIncPassword; 
     originalPassword = actualPassword; 
     if (newEncryptedPassword == originalPassword) 
     { 

      return true; 
     } 

     else { return false; } 

    } 
+0

Si desea crear un proveedor de membresía personalizado, primero debe heredar de MemberShipProvider. Y esto está bastante bien documentado si googleas un poco. –

+2

No intente desplegar sus propios esquemas personalizados de autenticación y administración de sesión o cree sus propios controles a menos que realmente no tenga otra opción. Solo quiero hacerlo, no califica. Una lectura interesante: http://www.troyhunt.com/2010/07/owasp-top-10-for-net-developers-part-3.html –

+0

@ChristopheGeers Exactamente ... Es bastante engorroso hacerlo tú mismo, los integrados en MembershipProviders funcionan bien, pero deben configurarse para hacerlo. – sinni800

Respuesta

1

Supongamos que tenemos una mesa para las cuentas de este tipo

enter image description here

A continuación, puede crear una cierta clase de ayuda que devuelve un objeto de cuenta

private static Account GetByName(string accountName, bool activatedOnly = false) 
{ 
    using (var context = new DBEntities()) 
    { 
     return context.Accounts.FirstOrDefault(s => 
      s.AccountName == accountName && 
      s.IsApproved == activatedOnly); 
    } 
} 

public static Account Get(string accountName, string password) 
{ 
    var account = GetByName(accountName, true); 
    if (account != null) 
     if (!Cryptographer.IsValidPassword(password, 
              account.PasswordSalt, 
              account.PasswordKey)) 
      return null; 
    return account; 
} 

Estoy usando EntityFramework pero no es importante aquí. La idea principal es mostrar que no necesita obtener toda la lista de cuentas (especialmente si tiene una gran lista de usuarios).
Mi clase Cryptographer parece

public class Cryptographer 
{ 
    private const int keyByteLength = 20; 
    public static void Encrypt(string password, 
           out byte[] salt, 
           out byte[] key) 
    { 
     using (var deriveBytes = new Rfc2898DeriveBytes(password, 
                 keyByteLength)) 
     { 
      salt = deriveBytes.Salt; 
      key = deriveBytes.GetBytes(keyByteLength); 
     } 
    } 
    public static bool IsValidPassword(string password, 
             byte[] salt, 
             byte[] key) 
    { 
     using (var deriveBytes = new Rfc2898DeriveBytes(password, salt)) 
     { 
      byte[] newKey = deriveBytes.GetBytes(keyByteLength); 
      return newKey.SequenceEqual(key); 
     } 
    } 
} 

De cource se puede implementar el algoritmo de su cuenta.

+0

Gracias, este es exactamente el tipo de comentarios que estaba buscando ... Con respecto al uso de Rfc2898DeriveBytes vs RNGCryptoServiceProvider y FormsAuthentication.HashPasswordForStoringInConfigFile ... ¿Cuál de los siguientes tiene el algoritmo hashing más fuerte? En cuanto a obtener una lista completa de usuarios, otros métodos realmente manejan conseguir que el usuario específico compruebe la contraseña, el incUserID limita la verificación de contraseña a solo esa, entonces me refiero a que selecciona contra toda la base de datos con solo 1 devolución, pero el EntityFramework haría exactamente lo mismo ¿no? – user1474120

+0

@ user1474120 - El principal problema que vas a tener es escribir consultas SQL seguras. Según su propio código, no usa un esquema de contraseña segura que es un problema, pero obtener el usuario y la contraseña de forma segura es un problema mayor. –

+0

@ user1474120, eche un vistazo a [this] (http://security.stackexchange.com/questions/2051/is-pbkdf2-based-system-cryptology-rfc2898derivebytes-better-for-unicode-pass) – Shymep

Cuestiones relacionadas