2011-02-09 14 views
14

Znajduję zaskakująco mało informacji na temat konwersji istniejącej bazy danych z zaszyfrowanych haseł do haseł Hashed. (Udało mi się znaleźć nieco więcej informacji na temat konwersji w drugą stronę, ale nie było to zbyt pomocne).Zmiana hasła z zaszyfrowanego na Hashed

Jak większość ludzi wie, zmiana ustawienia 01.w pliku web.config wpływa tylko na nowych użytkowników. Mam bazę danych z kilkoma setkami użytkowników i chciałbym je przekonwertować, aby używać hashowanych haseł bez zmiany istniejących haseł.

Czy ktoś jeszcze zna sposób, w jaki można to podejść? Dzięki za wszelkie wskazówki.

Odpowiedz

12

To podejście chciałbym zacząć, aby zobaczyć, jak daleko mam:

  1. Utwórz dwa MembershipProviders w moim web.config, jeden dla zaszyfrowany hasła i jeden zaszyfrowany.
  2. Przeprowadź pętlę przez wszystkich użytkowników za pomocą zaszyfrowanego dostawcy haseł. (SqlMembershipProvider.GetAllUsers)
  3. Uzyskaj hasło użytkownika za pomocą dostawcy zaszyfrowanego hasła. (MembershipUser.GetPassword)
  4. Zmiana hasła użytkownika na to samo hasło za pomocą hashowanego dostawcy haseł. (MembershipUser.ChangePassword)

Więc to byłoby coś takiego:

<membership defaultProvider="HashedProvider"> 
     <providers> 
      <clear /> 
      <add name="HashedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="false" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Hashed" type="System.Web.Security.SqlMembershipProvider" /> 
      <add name="EncryptedProvider" connectionStringName="MembershipConnectionString" enablePasswordRetrieval="true" requiresQuestionAndAnswer="false" applicationName="MyApp" passwordFormat="Encrypted" type="System.Web.Security.SqlMembershipProvider" /> 
     </providers> 
    </membership> 

Kod:

SqlMembershipProvider hashedProvider = (SqlMembershipProvider)Membership.Providers["HashedProvider"]; 
SqlMembershipProvider encryptedProvider = (SqlMembershipProvider)Membership.Providers["EncryptedProvider"]; 

int unimportant; 
foreach (MembershipUser user in encryptedProvider.GetAllUsers(0, Int32.MaxValue, out unimportant)) 
{ 
    hashedProvider.ChangePassword(user.UserName, user.GetPassword(), user.GetPassword()); 
} 
+1

Obecnie próbuję aktualizować jasne hasła tekstowe do zaszyfrowanych haseł. Chcę, żeby je uśpili, ale klient nie. W każdym razie to rozwiązanie wygląda obiecująco. Bardzo elegancki w swojej prostocie. Mam nadzieję, że to działa. – mikesigs

+2

Mam to działa, ale zastrzeżenia były zbyt wiele do zniesienia. Przede wszystkim nie możesz po prostu wywołać ChangePassword na mieszanym dostawcy, ponieważ musisz podać istniejące hasło (które próbuje mieszać w celu porównania z wartością bazy danych, która nie jest mieszana). Musisz więc wywołać ResetPassword, aby uzyskać tymczasowe hashowane hasło w celu wywołania ChangePassword. Występ jest zabójcą. Musisz pobrać każdego użytkownika MembershipUser, a następnie wywołać GetPassword, ResetPassword i ChangePassword dla każdego z nich. Ponad 3 * N trafień na db! Zawinęłem ją w transakcję i szybko wyczerpałem swoją pulę połączeń. – mikesigs

+0

Mam zamiar zbadać procedurę przechowywaną CLR, dzięki czemu mogę wywołać mechanizmy szyfrowania dostawcy z SQL. Odpowiem, jeśli to zadziała. – mikesigs

1

Ostrzegam was przed haszowaniem haseł, ponieważ jest wiele zastrzeżeń do takiego podejścia. Ta Blog post about hashing passwords była dla mnie bardzo wnikliwa i myślę, że powinieneś ją przeczytać. Dlaczego chcesz zaszyfrowane hasła zamiast szyfrowane?

+3

Dzięki za link, była to ciekawa lektura. Powiedział, że żadna metoda nie jest w 100% bezpieczna, a hash hash to obecny standard branżowy dotyczący przechowywania haseł. Skonfigurowałem swoją witrynę, aby używać zaszyfrowanych haseł dla wygody użytkowników (mogę do nich wysłać e-mailem), ale otrzymałem skargi, które stanowiły zagrożenie dla moich użytkowników, zwłaszcza gdy używają tego samego hasła w wielu witrynach. –

2

Ze względów bezpieczeństwa decyzja o przejściu z zaszyfrowanych haseł do haszy w bazie danych jest słuszna.

Generalnie do tworzenia skrótów Spośród istniejących zaszyfrowanych haseł, należy najpierw odszyfrować je, a następnie mieszania ich. Pamiętaj, że utracisz (kiedy w końcu zmienisz) oryginalne hasła. Zamiast tego będziesz mieć unikalny odcisk palca (hash) haseł użytkowników.

Pomyśl także o używaniu soli do mieszaja (obrony przed rainbow tables etc.), a także spojrzeć w zwolnionym algorytmów mieszaja jak BCrypt (Codeplex & Article: How To Safely Store A Password) Ze względów bezpieczeństwa zamiast szybkich tacy jak MD5.

Należy również pamiętać, że w przyszłości znacznie trudniej będzie zmienić algorytm mieszający niż zmienić go z funkcji szyfrowania na wartość mieszania. Więc chcesz zrobić to dobrze za pierwszym razem;)

+0

Tak, rozumiem, co zahasło hasła i jak nie można konwertować z hashe na oryginalne hasło. I wiem, że muszę odszyfrować zaszyfrowane hasła, a następnie je zaszyfrować. Nie wiem, jak mogę to zrobić dla wszystkich rekordów w sposób, który będzie wtedy działał z członkostwem ASP.NET. (BTW, czy członkostwo ASP.NET nie korzysta z soli dla haseł hashed?) –

+1

Algorytm mieszania domyślnego członkostwa ASP.NET to SHA1 i używają one soli zakodowanej jako Base64. –

12

rozwiązanie Grega to dobry początek, ale to nie będzie miało wpływu istniejących użytkowników. SqlMembershipProvider chroni istniejących użytkowników i hasła poprzez przechowywanie w tabeli PasswordFormat (0 = jasne, 1 = Hashhed, 2 = Encrypted) wraz z hasłami. Zmiana formatu hasła dostawcy ma wpływ tylko na wstawianie do tabel użytkowników.Aby przekonwertować hasła użytkowników istniejących na Hashed, należy zmienić parametr PasswordFormat dla każdego wpisu. Oto prosty sposób:

void HashAllPasswords() 
{ 
    var clearProvider = Membership.Providers["SqlProvider_Clear"]; 
    var hashedProvider = Membership.Providers["SqlProvider_Hashed"]; 
    int dontCare; 
    if (clearProvider == null || hashedProvider == null) return; 
    var passwords = clearProvider.GetAllUsers(0, int.MaxValue, out dontCare) 
     .Cast<MembershipUser>().ToDictionary(u => u.UserName, u => u.GetPassword()); 

    using (var conn = new SqlConnection(
      ConfigurationManager.ConnectionStrings[0].ConnectionString)) 
    { 
     conn.Open(); 
     using (var cmd = new SqlCommand(
       "UPDATE [aspnet_Membership] SET [PasswordFormat]=1", conn)) 
      cmd.ExecuteNonQuery(); 
    } 

    foreach (var entry in passwords) 
    { 
     var resetPassword = hashedProvider.ResetPassword(entry.Key, null); 
     hashedProvider.ChangePassword(entry.Key, resetPassword, entry.Value); 
    } 
} 
+0

Dzięki za spóźnioną odpowiedź. W rzeczywistości to zadanie jest wciąż na moim backburner i naprawdę nie miałem konkretnej techniki. Będę badać ten kod głębiej, kiedy znajdę trochę czasu. –

+0

+1 działa idealnie – ajbeaven

+0

Podczas uzyskiwania wszystkich haseł użytkowników należy filtrować zablokowanych użytkowników. W przeciwnym razie nie uda się na etapie resetowania/zmiany hasła. –