2012-06-22 13 views
5

Jestem CS-dur i właśnie skończyłem projektowanie strony ASP.net, a dla witryny potrzebowałem systemu uwierzytelniania logowania ... Nie chciałem używać SQLMembershipProvider, ponieważ naprawdę chciałem się uczyć jak zrobić to na własną rękę ... W każdym razie to jest to, co wymyśliłem, i zastanawiałem się, czy ktoś może dać mi jakieś uwagi, porady lub porady.Uwierzytelnienie ASP.net

Dzięki z góry

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

Jeśli chcesz utworzyć dostawcę niestandardowego członkostwa, musisz najpierw dziedziczyć z MemberShipProvider. I to jest dość dobrze udokumentowane, jeśli trochę google. –

+2

Nie należy wdrażać własnych schematów uwierzytelniania i zarządzania sesjami ani tworzyć własnych elementów sterujących, chyba że nie ma się innego wyboru. Po prostu chcę to zrobić, nie kwalifikuję się. Ciekawa lektura: http://www.troyhunt.com/2010/07/owasp-top-10-for-net-developers-part-3.html –

+0

@ChristopheGeers Dokładnie ... Wykonanie tego samemu jest dość kłopotliwe, wbudowane MembershipProviders działają dobrze, muszą być skonfigurowane, aby to zrobić. – sinni800

Odpowiedz

1

Załóżmy, że mamy tabelę dla kont jak ten

enter image description here

Następnie można utworzyć niektóre klasy pomocnika, który zwraca obiekt konto

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; 
} 

Używam EntityFramework, ale tutaj nie ma to znaczenia. Główną ideą jest pokazanie, że nie musisz mieć całej listy kont (szczególnie jeśli masz dużą listę użytkowników).
Moja Cryptographer klasa wygląda

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); 
     } 
    } 
} 

cource można zaimplementować algorytm własną rękę.

+0

Dziękuję, to jest dokładnie ten typ opinii, którego szukałem ... Odnośnie używania Rfc2898DeriveBytes vs RNGCryptoServiceProvider i FormsAuthentication.HashPasswordForStoringInConfigFile ... Który ma silniejszy algorytm mieszający? Jeśli chodzi o uzyskanie całej listy użytkowników, inne metody faktycznie radzą sobie z tym, aby konkretny użytkownik sprawdził hasło, a incUserID ogranicza sprawdzanie hasła tylko do tego, więc mam na myśli, że wybrał on całą bazę danych z tylko jednym powrotem, ale EntityFramework zrobiłby dokładnie to samo, prawda? – user1474120

+0

@ user1474120 - Głównym problemem będzie pisanie bezpiecznych zapytań SQL. Opierając się na własnym kodzie, nie używasz bezpiecznego schematu haseł, co stanowi problem, ale trudniejszym problemem jest uzyskanie użytkownika i hasła w bezpieczny sposób. –

+0

@ user1474120, spójrz na [this] (http://security.stackexchange.com/questions/2051/is-pbkdf2-based-system-cryptology-rfc2898derivebytes-better-for-unicode-pass) – Shymep

Powiązane problemy