• @Html.AntiForgeryToken() 源码分析,表单防伪码的生成


    源码来自MVC4
    @Html.AntiForgeryToken() 源码分析

    public MvcHtmlString AntiForgeryToken()
    {
        return new MvcHtmlString(AntiForgery.GetHtml().ToString());
    }

    AntiForgery源自System.Web.Helpers.AntiForgery

    复制代码
    public static HtmlString GetHtml()
    {
        if (HttpContext.Current == null)
        {
            throw new ArgumentException(WebPageResources.HttpContextUnavailable);
        }
        TagBuilder formInputElement = AntiForgery._worker.GetFormInputElement(new HttpContextWrapper(HttpContext.Current));
        return formInputElement.ToHtmlString(TagRenderMode.SelfClosing);
    }
    复制代码

    //查到_worker的创建
    private static readonly AntiForgeryWorker _worker = AntiForgery.CreateSingletonAntiForgeryWorker();

    //发现IAntiForgeryTokenSerializer来自AntiForgeryTokenSerializer
    //而且发现用所以接口的实例对象,开始查看具体代码实现

    复制代码
    private static AntiForgeryWorker CreateSingletonAntiForgeryWorker()
    {
        ICryptoSystem cryptoSystem = MachineKey45CryptoSystem.Instance;
        if (cryptoSystem == null)
        {
            cryptoSystem = new MachineKey40CryptoSystem();
        }
        IAntiForgeryConfig config = new AntiForgeryConfigWrapper();
        IAntiForgeryTokenSerializer serializer = new AntiForgeryTokenSerializer(cryptoSystem);
        ITokenStore tokenStore = new AntiForgeryTokenStore(config, serializer);
        IClaimUidExtractor claimUidExtractor = new ClaimUidExtractor(config, ClaimsIdentityConverter.Default);
        ITokenValidator validator = new TokenValidator(config, claimUidExtractor);
        return new AntiForgeryWorker(serializer, config, tokenStore, validator);
    }
    复制代码

    //_worker的GetFormInputElement,发现value是_serializer.Serialize序列出来的,于是查看AntiForgeryTokenSerializer对象

    复制代码
    public TagBuilder GetFormInputElement(HttpContextBase httpContext)
    {
        this.CheckSSLConfig(httpContext);
        AntiForgeryToken cookieTokenNoThrow = this.GetCookieTokenNoThrow(httpContext);
        AntiForgeryToken antiForgeryToken;
        AntiForgeryToken token;
        this.GetTokens(httpContext, cookieTokenNoThrow, out antiForgeryToken, out token);
        if (antiForgeryToken != null)
        {
            this._tokenStore.SaveCookieToken(httpContext, antiForgeryToken);
        }
        TagBuilder tagBuilder = new TagBuilder("input");
        tagBuilder.Attributes["type"] = "hidden";
        tagBuilder.Attributes["name"] = this._config.FormFieldName;
        tagBuilder.Attributes["value"] = this._serializer.Serialize(token);
        return tagBuilder;
    }
    复制代码

    //查到AntiForgeryTokenSerializer对象的Serialize函数

    复制代码
    public string Serialize(AntiForgeryToken token)
    {
        string result;
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
            {
                binaryWriter.Write(1);
                binaryWriter.Write(token.SecurityToken.GetData());
                binaryWriter.Write(token.IsSessionToken);
                if (!token.IsSessionToken)
                {
                    if (token.ClaimUid != null)
                    {
                        binaryWriter.Write(true);
                        binaryWriter.Write(token.ClaimUid.GetData());
                    }
                    else
                    {
                        binaryWriter.Write(false);
                        binaryWriter.Write(token.Username);
                    }
                    binaryWriter.Write(token.AdditionalData);
                }
                binaryWriter.Flush();
                result = this._cryptoSystem.Protect(memoryStream.ToArray());
            }
        }
        return result;
    }
    复制代码

    /关键的序列化函数
    //产生疑惑token.SecurityToken.GetData(),这个数据哪里来的
    //token.IsSessionToken这个是bool,看命名就知道是用来判断是不是生成关联session的token


    //退回后查看AntiForgeryToken这个class
    //
    //发现这段 GetFormInputElement函数里面如此创建

    AntiForgeryToken token;
    this.GetTokens(httpContext, cookieTokenNoThrow, out antiForgeryToken, out token);


    //通过上方查看_worker知道的实例
    // ITokenStore tokenStore = new AntiForgeryTokenStore(config, serializer);
    //查到

    复制代码
    private void GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, out AntiForgeryToken newCookieToken, out AntiForgeryToken formToken)
    {
        newCookieToken = null;
        if (!this._validator.IsCookieTokenValid(oldCookieToken))
        {
            AntiForgeryToken antiForgeryToken;
            newCookieToken = (antiForgeryToken = this._validator.GenerateCookieToken());
            oldCookieToken = antiForgeryToken;
        }
        formToken = this._validator.GenerateFormToken(httpContext, AntiForgeryWorker.ExtractIdentity(httpContext), oldCookieToken);
    }
    复制代码

    //继续追看

    复制代码
    public AntiForgeryToken GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken)
    {
        AntiForgeryToken antiForgeryToken = new AntiForgeryToken
        {
            SecurityToken = cookieToken.SecurityToken,
            IsSessionToken = false//原来默认是false,暂时认为默认是不使用session的
        };
        bool flag = false;
        if (identity != null && identity.IsAuthenticated)
        {
            if (!this._config.SuppressIdentityHeuristicChecks)
            {
                flag = true;
            }
            antiForgeryToken.ClaimUid = this._claimUidExtractor.ExtractClaimUid(identity);
            if (antiForgeryToken.ClaimUid == null)
            {
                antiForgeryToken.Username = identity.Name;
            }
        }
        if (this._config.AdditionalDataProvider != null)
        {
            antiForgeryToken.AdditionalData = this._config.AdditionalDataProvider.GetAdditionalData(httpContext);
        }
        if (flag && string.IsNullOrEmpty(antiForgeryToken.Username) && antiForgeryToken.ClaimUid == null && string.IsNullOrEmpty(antiForgeryToken.AdditionalData))
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, WebPageResources.TokenValidator_AuthenticatedUserWithoutUsername, new object[]
            {
                identity.GetType()
            }));
        }
        return antiForgeryToken;
    }
    复制代码

    //经过这样一看token的创建就清晰了


    //接着查看token的token.SecurityToken这个属性

    复制代码
    public BinaryBlob SecurityToken
    {
        get
        {
            if (this._securityToken == null)
            {
                this._securityToken = new BinaryBlob(128);//发现默认是128,对象是BinaryBlob
            }
            return this._securityToken;
        }
        set
        {
            this._securityToken = value;
        }
    }
    复制代码

    //查看BinaryBlob的构造函数,出现一个GenerateNewToken函数

    public BinaryBlob(int bitLength) : this(bitLength, BinaryBlob.GenerateNewToken(bitLength))
    {
    }

    //GenerateNewToken源码

    复制代码
    private static byte[] GenerateNewToken(int bitLength)
    {
        byte[] array = new byte[bitLength / 8];
        BinaryBlob._prng.GetBytes(array);
        return array;
    }
    复制代码

    //该死,有出现一个未知的东西,_prng
    private static readonly RNGCryptoServiceProvider _prng = new RNGCryptoServiceProvider();

    复制代码
    [SecuritySafeCritical]
    public override void GetBytes(byte[] data)
    {
        if (data == null)
        {
            throw new ArgumentNullException("data");
        }
        RNGCryptoServiceProvider.GetBytes(this.m_safeProvHandle, data, data.Length);
    }
    
    [SecurityCritical, SuppressUnmanagedCodeSecurity]
    [DllImport("QCall", CharSet = CharSet.Unicode)]
    private static extern void GetBytes(SafeProvHandle hProv, byte[] randomBytes, int count);
    复制代码

    //至此必应了一下RNGCryptoServiceProvider类(bing查msdn特别方便)
    //https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.rngcryptoserviceprovider(v=vs.110).aspx
    //http://www.cnblogs.com/izanami/archive/2011/04/20/2022173.html
    原来RNGCryptoServiceProvider的GetBytes用经过加密的强随机值序列填充字节数组,最终的随机数据生成!

    复制代码
    //现在这段序列化的部分已经解开了一些了
    binaryWriter.Write(1);
    binaryWriter.Write(token.SecurityToken.GetData());//数据明了,一段用经过加密的强随机值数组
    binaryWriter.Write(token.IsSessionToken);//Bool判断是否使用session
    if (!token.IsSessionToken)
    {
        if (token.ClaimUid != null)
        {
            binaryWriter.Write(true);
            binaryWriter.Write(token.ClaimUid.GetData());//也是一个BinaryBlob
        }
        else
        {
            binaryWriter.Write(false);
            binaryWriter.Write(token.Username);
        }
        binaryWriter.Write(token.AdditionalData);
    }
    binaryWriter.Flush();
    result = this._cryptoSystem.Protect(memoryStream.ToArray());
    复制代码


    //继续解开ClaimUid
    //在上文的 GenerateFormToken发现这样的一段
    antiForgeryToken.ClaimUid = this._claimUidExtractor.ExtractClaimUid(identity);
    //_claimUidExtractor在创建的地方是ClaimUidExtractor
    //发现源码

    复制代码
    public BinaryBlob ExtractClaimUid(IIdentity identity)
    {
        if (identity == null || !identity.IsAuthenticated || this._config.SuppressIdentityHeuristicChecks)
        {
            return null;
        }
        ClaimsIdentity claimsIdentity = this._claimsIdentityConverter.TryConvert(identity);
        if (claimsIdentity == null)
        {
            return null;
        }
        string[] uniqueIdentifierParameters = ClaimUidExtractor.GetUniqueIdentifierParameters(claimsIdentity, this._config.UniqueClaimTypeIdentifier);
        byte[] data = CryptoUtil.ComputeSHA256(uniqueIdentifierParameters);
        return new BinaryBlob(256, data);
    }
    复制代码
    复制代码
    public static byte[] ComputeSHA256(IList<string> parameters)
    {
        byte[] result;
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
            {
                foreach (string current in parameters)
                {
                    binaryWriter.Write(current);
                }
                binaryWriter.Flush();
                using (SHA256 sHA = CryptoUtil._sha256Factory())
                {
                    byte[] array = sHA.ComputeHash(memoryStream.GetBuffer(), 0, checked((int)memoryStream.Length));
                    result = array;
                }
            }
        }
        return result;
    }
    复制代码

    //发现是SHA256的哈希计算值
    //然后是AdditionalData

    复制代码
    public string AdditionalData
    {
        get
        {
            return this._additionalData ?? string.Empty;
        }
        set
        {
            this._additionalData = value;
        }
    }
    复制代码

    //最后是这句result = this._cryptoSystem.Protect(memoryStream.ToArray());
    //MachineKey40CryptoSystem : ICryptoSystem

    复制代码
    public string Protect(byte[] data)
    {
        byte[] array = new byte[data.Length + 4];
        Buffer.BlockCopy(data, 0, array, 4, data.Length);
        array[0] = 133;
        array[1] = 135;
        array[2] = 242;
        array[3] = 102;
        string hex = this._encoder(array, MachineKeyProtection.All);
        return MachineKey40CryptoSystem.HexToBase64(hex);
    }
    
    internal static string HexToBase64(string hex)
    {
        int num = hex.Length / 2;
        byte[] array = new byte[num];
        for (int i = 0; i < num; i++)
        {
            array[i] = (byte)((MachineKey40CryptoSystem.HexValue(hex[i * 2]) << 4) + MachineKey40CryptoSystem.HexValue(hex[i * 2 + 1]));
        }
        return HttpServerUtility.UrlTokenEncode(array);
    }
    复制代码

    //将那些随机生成的数据变成了16进制字符串
    //加密到此结束了

    //最后就是对应的解密了

    复制代码
    public AntiForgeryToken Deserialize(string serializedToken)
    {
        try
        {
            using (MemoryStream memoryStream = new MemoryStream(this._cryptoSystem.Unprotect(serializedToken)))
            {
                using (BinaryReader binaryReader = new BinaryReader(memoryStream))
                {
                    AntiForgeryToken antiForgeryToken = AntiForgeryTokenSerializer.DeserializeImpl(binaryReader);
                    if (antiForgeryToken != null)
                    {
                        return antiForgeryToken;
                    }
                }
            }
        }
        catch
        {
        }
        throw HttpAntiForgeryException.CreateDeserializationFailedException();
    }
    
    
    private static AntiForgeryToken DeserializeImpl(BinaryReader reader)
    {
        byte b = reader.ReadByte();//从当前流中读取下一个字节,并使流的当前位置提升 1 个字节。
        if (b != 1)//对应加密的binaryWriter.Write(1);
        {
            return null;
        }
        //依照加密时候的分段大小对应解密
        AntiForgeryToken antiForgeryToken = new AntiForgeryToken();
        byte[] data = reader.ReadBytes(16);
        antiForgeryToken.SecurityToken = new BinaryBlob(128, data);
        antiForgeryToken.IsSessionToken = reader.ReadBoolean();
        if (!antiForgeryToken.IsSessionToken)
        {
            bool flag = reader.ReadBoolean();
            if (flag)
            {
                byte[] data2 = reader.ReadBytes(32);
                antiForgeryToken.ClaimUid = new BinaryBlob(256, data2);
            }
            else
            {
                antiForgeryToken.Username = reader.ReadString();
            }
            antiForgeryToken.AdditionalData = reader.ReadString();
        }
        if (reader.BaseStream.ReadByte() != -1)
        {
            return null;
        }
        return antiForgeryToken;
    }
     

    文章系转载 http://www.cnblogs.com/RainbowInTheSky/p/5565248.html

  • 相关阅读:
    Spring 框架的概述以及Spring中基于XML的IOC配置
    SpringBoot(1)
    C/C++经典程序之打印三角形
    C++构造函数详解(复制构造函数)
    利用函数模板计算并返回数组d 中size个元素的平方和
    C++模板之typename和class关键字的区别
    构造函数与成员函数的区别?
    为什么多数穷人很难逆袭成功
    用递归方式求解这个问题:一只母兔从四岁开始每年生一只小母兔,按此规律,第n年有多少只母兔?
    编写一个函数 reverseDigit(int num).该函数读入一个整数,然后将这个整数的每个位上的数字逆序输出。
  • 原文地址:https://www.cnblogs.com/sunice/p/6294907.html
Copyright © 2020-2023  润新知