日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

.NET Core验证ASP.NET密码

發(fā)布時(shí)間:2023/12/4 asp.net 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core验证ASP.NET密码 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

.NET Core驗(yàn)證ASP.NET密碼

隨著?.NETCore的持續(xù)更新和完善,越來(lái)越多的機(jī)構(gòu)已經(jīng)選擇或者升級(jí)為?.NETCore。但由于技術(shù)不完全相同,不可能所有應(yīng)用/數(shù)據(jù)庫(kù)都能無(wú)縫遷移,因此?ASP.NETCore和傳統(tǒng)?ASP.NET之間多少會(huì)存在一些挑戰(zhàn),需要更多的漸進(jìn)升級(jí)方法和交互。

其中,密碼共享就是升級(jí)到?ASP.NETCore一個(gè)很容易想到的漸進(jìn)升級(jí)方式,也是一個(gè)需要解決的問(wèn)題。

啥?什么都不用做?

其實(shí)如果堅(jiān)持走?ASP.NETCoreIdentity這一套,代碼是寫(xiě)了一個(gè)?if/else,能兼容老?ASP.NETIdentity生成的密碼的。?Github鏈接:https://github.com/dotnet/aspnetcore/blob/8b7f6621695d93b2a55fb8a5b1be99c4af867ae4/src/Identity/Extensions.Core/src/PasswordHasher.cs#L185-L207,核心代碼如下:

/// <summary> /// Returns a <see cref="PasswordVerificationResult"/> indicating the result of a password hash comparison. /// </summary> /// <param name="user">The user whose password should be verified.</param> /// <param name="hashedPassword">The hash value for a user's stored password.</param> /// <param name="providedPassword">The password supplied for comparison.</param> /// <returns>A <see cref="PasswordVerificationResult"/> indicating the result of a password hash comparison.</returns> /// <remarks>Implementations of this method should be time consistent.</remarks> public virtual PasswordVerificationResult VerifyHashedPassword(TUser user, string hashedPassword, string providedPassword) {if (hashedPassword == null){throw new ArgumentNullException(nameof(hashedPassword));}if (providedPassword == null){throw new ArgumentNullException(nameof(providedPassword));}byte[] decodedHashedPassword = Convert.FromBase64String(hashedPassword);// read the format marker from the hashed passwordif (decodedHashedPassword.Length == 0){return PasswordVerificationResult.Failed;}switch (decodedHashedPassword[0]){case 0x00:if (VerifyHashedPasswordV2(decodedHashedPassword, providedPassword)){// This is an old password hash format - the caller needs to rehash if we're not running in an older compat mode.return (_compatibilityMode == PasswordHasherCompatibilityMode.IdentityV3)? PasswordVerificationResult.SuccessRehashNeeded: PasswordVerificationResult.Success;}else{return PasswordVerificationResult.Failed;}case 0x01:int embeddedIterCount;if (VerifyHashedPasswordV3(decodedHashedPassword, providedPassword, out embeddedIterCount)){// If this hasher was configured with a higher iteration count, change the entry now.return (embeddedIterCount < _iterCount)? PasswordVerificationResult.SuccessRehashNeeded: PasswordVerificationResult.Success;}else{return PasswordVerificationResult.Failed;}default:return PasswordVerificationResult.Failed; // unknown format marker} }

它根據(jù)?Base64解碼后的第一個(gè)字節(jié),來(lái)判斷是老版本還是新版本,然后調(diào)用各自不同的驗(yàn)證函數(shù)。

但時(shí)代在變化,很多人已經(jīng)不用官方提供的這一套?Identity驗(yàn)證密碼,那么有什么“騷”操作,可以解密嗎?

和密碼剛正面

傳統(tǒng)的?ASP.NET MVC模板項(xiàng)目是通過(guò)?ASP.NETIdentity管理的密碼,它由?Rfc2898DeriveBytes實(shí)現(xiàn),該算法進(jìn)行了?1000次循環(huán)?SHA1哈希、并加鹽,以確保難以通過(guò)傳統(tǒng)的哈希碰撞來(lái)確保密碼的安全性,其核心代碼如下(?Github鏈接:https://github.com/aspnet/AspNetIdentity/blob/9c48993a446288032f9824633e6dae81257da06e/src/Microsoft.AspNet.Identity.Core/Crypto.cs#L26-L46):

private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes private const int PBKDF2SubkeyLength = 256/8; // 256 bits private const int SaltSize = 128/8; // 128 bits /* ======================= * HASHED PASSWORD FORMATS * ======================= * * Version 0: * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations. * (See also: SDL crypto guidelines v5.1, Part III) * Format: { 0x00, salt, subkey } */ public static string HashPassword(string password) {if (password == null){throw new ArgumentNullException("password");}// Produce a version 0 (see comment above) text hash.byte[] salt;byte[] subkey;using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount)){salt = deriveBytes.Salt;subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);}var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);return Convert.ToBase64String(outputBytes); }

值得一提的是,代碼用到了?Rfc2898DeriveBytes,經(jīng)常讀我的博客的知道,這個(gè)類(lèi)是老朋友了,通過(guò)傳入明文密碼、鹽、迭代次數(shù)和算法,可以在不依賴于哈希算法安全性的前提下做單向加密,確保了密碼的不可(難以)破解性。

可見(jiàn),密碼的原始字節(jié)由?{0,salt,subkey}三部分組成,其中鹽為?128位,即?16字節(jié),?subkey為?256位,即?32字節(jié),總共?1+16+32=49字節(jié),密文需要轉(zhuǎn)換為?Base64,根據(jù)?Base64的信息量計(jì)算公式

Math.Log(64, 256)=0.75

可知,?Base64編碼相對(duì)原始字節(jié)的比例為?0.75:1,因此計(jì)算可得轉(zhuǎn)換為?Base64之后,其字符串長(zhǎng)度為

Math.Ceiling(49 / 0.75 / 4) * 4 = 68

我們來(lái)從數(shù)據(jù)庫(kù)隨便查詢一個(gè)由?ASP.NETIdentity創(chuàng)建的密碼:

SELECT TOP 1 PasswordHash, LEN(PasswordHash) AS Len FROM [User]

結(jié)果如下,可見(jiàn)結(jié)果長(zhǎng)度真的為?68:?

所以,說(shuō)了這么多,怎么把密碼遷移到?ASP.NETCore呢?

注意看,上面的代碼沒(méi)什么特別,就是依賴于?Rfc2898DeriveBytes這個(gè)類(lèi)。

.NETCore內(nèi)置了?Rfc2898DeriveBytes這個(gè)類(lèi),可以直接使用,不需要安裝任何?NuGet包,因此……直接復(fù)制粘貼上文中的【核心代碼】即可。

ASP.NETCore中的?Identity有什么區(qū)別?

Github核心代碼在此:https://github.com/dotnet/aspnetcore/blob/8b7f6621695d93b2a55fb8a5b1be99c4af867ae4/src/Identity/Extensions.Core/src/PasswordHasher.cs#L113-L156

我就從簡(jiǎn)引用一下關(guān)鍵注釋:

/* ======================= * HASHED PASSWORD FORMATS * ======================= * * Version 2: * PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations. * (See also: SDL crypto guidelines v5.1, Part III) * Format: { 0x00, salt, subkey } * * Version 3: * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations. * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey } * (All UInt32s are stored big-endian.) */

原來(lái),老?ASP.NETIdentity中的密碼版本為?V2,當(dāng)前?ASP.NETCoreIdentity中的密碼版本為?V3,首字節(jié)(版本號(hào))從?0x00改成了?0x01,算法從?HMACSHA1升級(jí)為了?HMACSHA256,另外?V3版本還將迭代次數(shù)從?1000升級(jí)為?10000,另外還將算法名、迭代次數(shù)、鹽的長(zhǎng)度信息保存在了密碼中。

另外需要注意的是,新?ASP.NETCoreIdentity的實(shí)現(xiàn)很有彈性,它通過(guò)依賴注入?IOptions<T>的形式,使得所有選項(xiàng)都是可以配置的。

解密示例

假如我有一個(gè)密碼:?myF&TB9vhTx7,我使用傳統(tǒng)的?ASP.NET MVC創(chuàng)建項(xiàng)目,然后用這個(gè)密碼注冊(cè)一個(gè)帳號(hào):?

然后在數(shù)據(jù)庫(kù)中將哈希值取出來(lái):

SELECT PasswordHash FROM [AspNetUsers] WHERE [Email] = N'sdflysha@qq.com'

查得結(jié)果如下,結(jié)果為?AJRvdJ1/Ii+58zU6yBrPJH4hCkMagxqK/W6oejAuG1hIrNPEQMAAyYynsXWwat9Huw==:?

我將上述代碼作簡(jiǎn)化,用最簡(jiǎn)單的代碼表達(dá)驗(yàn)證密碼的過(guò)程,除去兩行注釋代碼(用于做斷言),整個(gè)過(guò)程只需7行代碼,代碼如下:

string pwdHashText = "AJRvdJ1/Ii+58zU6yBrPJH4hCkMagxqK/W6oejAuG1hIrNPEQMAAyYynsXWwat9Huw=="; string pwd = "myF&TB9vhTx7"; byte[] pwdHash = Convert.FromBase64String(pwdHashText); // Debug.Assert(pwdHash.Length == 49); // Debug.Assert(pwdHash[0] == 0); byte[] salt = pwdHash[1..17]; byte[] hash = pwdHash[17..49]; using var r = new Rfc2898DeriveBytes(pwd, salt, 1000); Console.WriteLine(r.GetBytes(32).SequenceEqual(hash));

此時(shí),運(yùn)行結(jié)果如下,運(yùn)行顯示?True,表示驗(yàn)證解碼成功:?

總結(jié)

我總結(jié)一個(gè)表格如下所示:


ASP.NETIdentityASP.NETCoreIdentity
版本V2V3
首字節(jié)0x000x01
默認(rèn)算法HMACSHA1HMACSHA256
迭代次數(shù)100010000
密碼信息版本+鹽+哈希值版本+算法+迭代次數(shù)+鹽長(zhǎng)度+鹽+哈希值
原始長(zhǎng)度1+16+32=491+4+4+4+16+32=61
Base64長(zhǎng)度6884
可配置性不可配置可自由配置
安全性非常好

密碼解密其實(shí)是前往?ASP.NETCore上較為輕松的一步,核心代碼也就?7行。

其實(shí)更有挑戰(zhàn)、也更有意思的是如何解傳統(tǒng)?ASP.NETIdentity中的?Cookie,我將在下一篇中詳情分析這個(gè)主題,敬請(qǐng)期待!

喜歡的朋友請(qǐng)關(guān)注我的微信公眾號(hào):【DotNet騷操作】

新年快到了,祝大家闔家歡樂(lè),鼠年大吉!

總結(jié)

以上是生活随笔為你收集整理的.NET Core验证ASP.NET密码的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。