zoukankan      html  css  js  c++  java
  • 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 旧加密方式. 马上解决...

  • 相关阅读:
    树结构中的左右值计算
    Gitlab Runner实现NetCore自动化持续集成
    使用docker搭建gitlab服务器
    Linux笔记
    Miniprofiler在swagger、vue、angular中的使用
    MySqlException: The user specified as a definer ('root'@'%') does not exist解决方法
    从NetCore报错到MySql安全
    Asp.NetCore+Microsoft.AspNetCore.SignalR前后端分离
    学习sqlserve的一些笔记
    再见Jenkins,从Gitlab代码提交到k8s服务持续交付只需七毛三(走过路过不要错过)
  • 原文地址:https://www.cnblogs.com/calvinK/p/3664725.html
Copyright © 2011-2022 走看看