天天看點

Asp.Net Form驗證不通過,重複登入(.net4,4.5form驗證相容性問題)

問題産生根源:

當然,其實應該需要保持線上所有機器環境一緻!可是,寫了一個小程式。使用的是4.5,aysnc/await實在太好用了,真心不想把代碼修改回去。

so,動了念頭,在這台伺服器上裝個4.5,ms不是說了麼,4.5和4.0是高度相容的。。。。。。

問題現象:

一台伺服器在安裝.net framework 4.5 之後,在該伺服器所部署的網站(使用.net framework 4,未修改任何配置,分布式環境),

網站在這台伺服器上登入之後,打開其他伺服器的任何站點,form驗證過不去,導緻重複登入,反之亦然.

問題分析:

為什麼會導緻重複登入問題?

很簡單能推斷出是在這個機器上安裝了4.5 ,某些元件的變動,導緻form驗證的加解密方式有變動.使得2台機器生成的登入cookie内容不一緻,不能互相解析.

能影響到.net對form加解密産生不同作用的地方無非2個.

1.本身代碼的bug,相容性問題問題。

2.配置影響(如web.config中的authentication,machineKey等).

1嘛,基本不可能,ms沒這麼渣,那就隻能從2下手,但是具體什麼配置影響到,就不得而知了.

通過參數配置,如果有改變,那對加解密産生的改變都是相符的. so,我們分析一下加密的方法,找出不同,通過參數來相容這些修改.那問題就解決了.

form驗證相關的方法,都在System.Web.Security.FormsAuthentication中.

通過調用加密方法在4.5上生成加密字元串,丢到4.0的機器上解密,不通過,提示加密字元串驗證不通過.

so,我們看看加密方法中做了什麼

加密方法:

省略部分代碼,剩下的關鍵代碼。

public static string Encrypt(FormsAuthenticationTicket ticket)
{
    return Encrypt(ticket, true);
}      
internal static string Encrypt(FormsAuthenticationTicket ticket, bool hexEncodedTicket)
{
    byte[] clearData = MakeTicketIntoBinaryBlob(ticket);
        if ((_Protection == FormsProtectionEnum.All) || (_Protection == FormsProtectionEnum.Encryption))
        {
            clearData = MachineKeySection.EncryptOrDecryptData(true, clearData, null, 0, clearData.Length, false, false, IVType.Random);
        }
    }
    return CryptoUtil.BinaryToHex(clearData);
}
      

然後我們繼續深入到MakeTicketIntoBinaryBlob中檢視

private static byte[] MakeTicketIntoBinaryBlob(FormsAuthenticationTicket ticket)
{
    if (!AppSettings.UseLegacyFormsAuthenticationTicketCompatibility)
    {
        return FormsAuthenticationTicketSerializer.Serialize(ticket);
    }
  ........................
}
      

對比4,4.5中MakeTicketIntoBinaryBlob方法代碼,發現4.5的源代碼中多了AppSettings.UseLegacyFormsAuthenticationTicketCompatibility這麼一個開關配置.

系統預設值為flase,so.在4.5中得到的加密字元串來自FormsAuthenticationTicketSerializer.Serialize(ticket).而4中是在後續代碼中.

so,增加配置<add key="aspnet:UseLegacyFormsAuthenticationTicketCompatibility" value="true" /> 相容到這部分.

然後,我們繼續看MachineKeySection.EncryptOrDecryptData(true, clearData, null, 0, clearData.Length, false, false, IVType.Random);

internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length, bool useValidationSymAlgo, bool useLegacyMode, IVType ivType)
{
    return EncryptOrDecryptData(fEncrypt, buf, modifier, start, length, useValidationSymAlgo, useLegacyMode, ivType, !AppSettings.UseLegacyEncryption);
}
      

很熟悉,又看到!AppSettings.UseLegacyEncryption開關配置.進入EncryptOrDecryptData方法中能看到這個參數影響到使用不同的加密方式.

同上,增加配置<add key="aspnet:UseLegacyEncryption" value="true" />相容到這部分.

再次調用Encrypt方法生成加密字元串,丢到4.0機器上.哇,能解密成功了.

當然,實際解決起來,走了不少彎路,周五晚上發現問題,查了一晚上,未果,但是有思路了.後又周一查了2個小時,終于搞定這個問題.

相關說明:

有關安全更新 2638420 的部署指南,請參見 MS11-100 如何配置 ASP.NET 中的舊加密模式

看了上面一個,好傻...如果發現問題的時候,之後搜尋asp.net 舊加密方式. 馬上解決...

繼續閱讀