English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Standardimplementierung und Anwendung von Microsoft.IdentityModel.CryptoLibraries.IPasswordHasher in ASP.NET

Wer MS Identity Authentifizierungssystem kennt, weiß sicherlich die Rolle des UserManager, er ist der Koordinator im gesamten System, er definiert ein Set von Benutzeraktionen, um uns zu helfen, Benutzerinformationen, Rolleninformationen zu verwalten und Passwörter zu behandeln. Und seine Implementierung liegt im UserStore, wir können ihn implementieren, wie IUserStore, IUserPasswordStore, IRoleStore usw. Wir können auf eine Gesamtheit von Benutzeraktionen zugreifen, um unsere eigenen Benutzerinformationen und Datenstrukturen sowie Datenlager zu definieren. Was den Password Hasher betrifft, bietet MS uns immer noch eine vollständige Verhaltensdefinition, die von UserManager koordiniert wird. Zum Beispiel

UserManager.PasswordHasher.HashPassword(password)

PasswordHasher wird im UserManager-Interface so definiert:

Ich war ursprünglich nicht daran interessiert, die Standardimplementierung zu verwenden, aus dem Grund, dass ich eine unabhängige Benutzerauthentifizierungsprojekt benötige, um als Authentifizierungsdienst zu dienen, der nur Token produziert, und nach erfolgreicher Authentifizierung die Benutzer HTTP Request Header mit Token verwendet, um auf verschiedene Ressourcen auf dem Anwendungsserver zuzugreifen.

Genau aus diesem Grund trat in mehreren Anwendungen ein solches Problem bei der Passwortauthentifizierung auf:

Zum Beispiel verwendet Anwendung A die Implementierung von IPasswordHasher, um einen benutzerdefinierten Verschlüsselungsweg - MD zu realisieren5+Salt-Form, während Anwendung B den Standard-PasswordHasher von Identity verwendet, um dies durch Reverse-Engineering zu erhalten:

Daß ich die Quellcode für verschiedene Verschlüsselungsmethoden in verschiedenen Anwendungen entpacken und die Standardverschlüsselungsmethode erhalten muss, um die Passwörter basierend auf dem Namen der Anwendung zu verschlüsseln oder zu entschlüsseln, oder direkt auf eine Weise zu vergleichen, wie die Datenbank und das von den Benutzern eingegebene Passwort übereinstimmen, werde ich hier die spezifische Implementierung des MS Default PasswordHasher auflisten.

// Decompiled with JetBrains decompiler
// Type: Microsoft.AspNet.Identity.Crypto
// Assembly: Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: E3A10FFD-023A-4BC3-AD53-32D145ABF1C9
// Assembly location: C:\Sport\NewProject\V2.0\Api\Fantasy.Sport\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll
using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
namespace Microsoft.AspNet.Identity
{
 internal static class Crypto
 {
 private const int PBKDF2IterCount = 1000;
 private const int PBKDF2SubkeyLength = 32;
 private const int SaltSize = 16;
 public static string HashPassword(string password)
 {
  if (password == null)
  throw new ArgumentNullException("password");
  byte[] salt;
  byte[] bytes;
  using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, 16, 1000))
  {
  salt = rfc2898DeriveBytes.Salt;
  bytes = rfc2898DeriveBytes.GetBytes(32);
  }
  byte[] inArray = new byte[49]);
  Buffer.BlockCopy((Array) salt, 0, (Array) inArray, 1, 16);
  Buffer.BlockCopy((Array) bytes, 0, (Array) inArray, 17, 32);
  return Convert.ToBase64String(inArray);
 }
 public static bool VerifyHashedPassword(string hashedPassword, string password)
 {
  if (hashedPassword == null)
  return false;
  if (password == null)
  throw new ArgumentNullException("password");
  byte[] numArray = Convert.FromBase64String(hashedPassword);
  if (numArray.Length != 49 || (int) numArray[0] != 0)
  return false;
  byte[] salt = new byte[16]);
  Buffer.BlockCopy((Array) numArray, 1, (Array) salt, 0, 16);
  byte[] a = new byte[32]);
  Buffer.BlockCopy((Array) numArray, 17, (Array) a, 0, 32);
  byte[] bytes;
  using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, 1000))
  bytes = rfc2898DeriveBytes.GetBytes(32);
  return Crypto.ByteArraysEqual(a, bytes);
 }
 [MethodImpl(MethodImplOptions.NoOptimization)]
 private static bool ByteArraysEqual(byte[] a, byte[] b)
 {
  if (object.ReferenceEquals((object) a, (object) b))
  return true;
  if (a == null || b == null || a.Length != b.Length)
  return false;
  bool flag = true;
  for (int index = 0; index < a.Length; ++index)
  flag &= (int) a[index] == (int) b[index];
  返回flag;
 }
 }
}

有人可能会问,拿到了这些源码要如何应用呢?下面就是简要介绍这个问题。

一开始我天真地认为,不就是一个加密吗?不用仔细看了,拿来用就好了?

在注册用户和修改密码时,都是通过上面的HashPassword方法进行密码加密的。那么我在新的自定义PasswordHasher中,为应用B对比用户登录密码时,为什么不直接将用户输入通过HashPassword加密一遍呢?因此我自定义的VerifyHashedPassword(核实)方法,就是比较数据库中的Pwd和经过hasher处理的结果是否相等。但结果是,每次相同的字符串会产生不同的加密结果,和以前玩md一样。5+盐值不一样。因此我又想到了其默认实现的VerifyHashedPassword方法。

因此最后要说明的是,您可以直接使用微软Identity的加密方式(上面的Hasher)进行,在比较用户输入和数据库中已经经过hash的存储结果时,使用其VerifyHashedPassword()方法。即使不使用Identity认证,也可以使用此加密算法。

以上就是本文的全部内容,希望本文的内容对大家的学习或工作能带来一定的帮助。同时也希望多多支持呐喊教程!

声明:本文内容来自网络,版权归原作者所有。内容由互联网用户自发贡献并自行上传,本网站不拥有所有权,未进行人工编辑处理,也不承担相关法律责任。如果您发现涉嫌版权的内容,请发送邮件至:notice#w。3codebox.com(在发送邮件时,请将#更换为@)进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。

Gefällt mir