web api接口安全设计(签名校验方式)

最原始接口:public string GetProjectInfo(string latest_update_time);

修改后接口:public string GetProjectInfo(string latest_update_time, string appKey, string timeStamp, string nonce, string signature);

添加参数:

appKey 接口Key
appSecret 接口密钥
timeStamp 时间戳 毫秒
nonceStr 随机字符串
signature 加密字符串

解决三个接口安全问题:

1.保证参数不被篡改

2.保证访问的合法性

3.保证请求的唯一性,防止暴力访问

签名校验的原理就是appSecret 只有你知我知,通过加入appSecret 加密生成的签名无法破解,这样就可到达确保参数不被修改,因为服务端会通过相同的算法生成签名,如果和传过来的签名不一样则代表参数发生了改表

签名算法 比如:signature =MD5(appKey +timeStamp +nonceStr +appSecret )

时间戳+随机字符串就可以防止接口被同一个请求重复调用

服务端设置一个时效时间,比如十分钟,十分钟内请求合理,在判断nonceStr 随机字符串在服务端是否有缓存,有的话也代表请求失效

接口定义:

 public string GetProjectInfo(string latest_update_time, string appKey, string timeStamp, string nonce, string signature);

/// <summary>
    /// 验证
    /// </summary>
    /// <param name="latest_update_time"></param>
    /// <param name="appKey"></param>
    /// <param name="timeStamp"></param>
    /// <param name="nonce"></param>
    /// <param name="signature"></param>
    public void Verification(string latest_update_time, string appKey, string timeStamp, string nonce, string signature)
    {
        try
        {
            DateTime update_time = DateTime.MinValue; string appSecret = "";
            //更新时间
            if (StringUtil.isNotNullOrBlank(latest_update_time))
            {
                if (!DateTime.TryParse(latest_update_time, out update_time))
                {
                    throw new Exception("参数latest_update_time格式不正确");
                }
            }
            else
            {
                throw new Exception("参数latest_update_time不能为空");
            }
            //appKey
            if (StringUtil.isNotNullOrBlank(appKey))
            {
                if (appDic.ContainsKey(appKey))
                {
                    appSecret = appDic[appKey];
                }
                else
                {
                    throw new Exception("参数appKey不合法");
                }
            }
            else
            {
                throw new Exception("参数appKey不能为空");
            }
            //timeStamp时间戳
            if (StringUtil.isNotNullOrBlank(timeStamp))
            {
                long currentTimeStamp = Convert.ToInt64(GetTimeStamp());
                //有效期60分钟
                if (Math.Abs(currentTimeStamp - Convert.ToInt64(timeStamp)) > (60 * 60 * 1000))
                {
                    throw new Exception("参数timeStamp已过期");
                }
            }
            else
            {
                throw new Exception("参数timeStamp不能为空");
            }
            //随机字符串
            if (StringUtil.isNotNullOrBlank(nonce))
            {
                if (CacheHelper.GetCache(nonce) == null)
                {
                    CacheHelper.SetCache(nonce, timeStamp, 10 * 60);
                }
                else
                {
                    throw new Exception("参数nonce已使用");
                }
            }
            else
            {
                throw new Exception("参数nonce不能为空");
            }
            //signature签名
            if (StringUtil.isNotNullOrBlank(signature))
            {
                string signTempStr = appSecret + latest_update_time + appKey + timeStamp + nonce + appSecret;
                string signResult = GenerateMD5(signTempStr);
                if (signature != signResult)
                {
                    throw new Exception("签名验证失败");
                }
            }
            else
            {
                throw new Exception("参数signature不能为空");
            }
        }
        catch (Exception)
        {

            throw;
        }
    }
    /// <summary>
    /// 获取时间戳 毫秒
    /// </summary>
    /// <returns></returns>
    public static string GetTimeStamp()
    {
        TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        return Convert.ToInt64(ts.TotalMilliseconds).ToString();
    }
    /// <summary>
    /// Md5加密 32位小写
    /// </summary>
    /// <param name="txt"></param>
    /// <returns></returns>
    public static string GenerateMD5(string str)
    {
        using (MD5 mi = MD5.Create())
        {
            byte[] buffer = Encoding.Default.GetBytes(str);
            //开始加密
            byte[] newBuffer = mi.ComputeHash(buffer);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < newBuffer.Length; i++)
            {
                sb.Append(newBuffer[i].ToString("x2"));
            }
            return sb.ToString();
        }
    }

 

posted @ 2022-04-01 16:01  林间山下  阅读(594)  评论(0编辑  收藏  举报