zoukankan      html  css  js  c++  java
  • 使用过滤器对mvc api接口安全加密

    asp.net api接口安全

    安全要求:

    b1.防伪装攻击(案例:在公共网络环境中,第三方 有意或恶意 的调用我们的接口)

    b2.防篡改攻击(案例:在公共网络环境中,请求头/查询字符串/内容 在传输过程被修改)

    b3.防重放攻击(案例:在公共网络环境中,请求被截获,稍后被重放或多次重放)

    b4.防数据信息泄漏(案例:截获用户登录请求,截获到账号、密码等)

    设计原则

    1.轻量级

    2.适合于异构系统(跨操作系统、多语言简易实现)

    3.易于开发

    4.易于测试

    5.易于部署

    6.满足接口安全需求(满足b1 b2 b3要求),无过度设计。

    其它:接口安全要求b4部分,主要针对目前用户中心的登录接口

    设计原则是:使用HTTPS安全协议 或 传输内容使用非对称加密,目前我们采用的后者

    适用范围

    1.所有写操作接口(增、删、改 操作)

    2.非公开的读接口(如:涉密/敏感/隐私 等信息)

    api 接口安全验证 过滤器代码

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Filters;
    using test.Models;
    using TEST.Common;
    
    namespace test.Filters
    {
        /*
         * 第一步:登录系统,获取appkey
         * 第二步:http请求头headers加入字段appid,sign,timestamp三个字段,appid:用户名,sign:签名值(后面详细解说),timestamp:当前时间戳 ,如:2017/12/12 17:11:9 值为: 1513069869
         * 第三步:把业务请求的参数传入到http消息体Body(x-www-form-urlencoded)
         * 第四步:计算sign值,对除签名外的所有请求参数按 参数名+值 做的升序排列,value值无需编码
         * 整个流程示例如下:
         *      appkey=D9U7YY5D7FF2748AED89E90HJ88881E6 (此参数不需要排序,而是加在文本开头和结尾处)
         * headers参数如下
         *      appid=user1
         *      sign=???
         *      timestamp=1513069265
         * body参数如下
         *      par1=52.8
         *      par2=这是一个测试参数
         *      par3=852
         * 
         * 1)按 参数名+值 以升序排序,结果:appiduser1par152.8par2这是一个测试参数par3852timestamp1513069265
         * 2)在本文开头和结尾加上登录时获取的appkey 结果为:D9U7YY5D7FF2748AED89E90HJ88881E6appiduser1par152.8par2这是一个测试参数par3852timestamp1513069265D9U7YY5D7FF2748AED89E90HJ88881E6
         * 3)对此文本进行md5 32位 大写 加密,此时就是sign值  结果为:B44C81F3DF4D5E8A614C84977D33E8D2  
         */
    
        /// <summary>
        /// api接口加密身份验证过滤器
        /// </summary>
        public class VerificationFilters : IAuthorizationFilter
        {
            /// <summary>
            /// 接口签名验证
            /// </summary>
            /// <param name="context"></param>
            public void OnAuthorization(AuthorizationFilterContext context)
            {
                ModelResult modelResult = new ModelResult();
                //参数判断
                if (!context.HttpContext.Request.Headers.ContainsKey("appid"))
                {
                    modelResult.code = -1;
                    modelResult.message = "缺少appid参数!";
                    JsonResult json = new JsonResult(modelResult);
                    context.Result = json;
                }
                else if (!context.HttpContext.Request.Headers.ContainsKey("sign"))
                {
                    modelResult.code = -1;
                    modelResult.message = "缺少sign参数!";
                    JsonResult json = new JsonResult(modelResult);
                    context.Result = json;
                }
                else if (!context.HttpContext.Request.Headers.ContainsKey("timestamp"))
                {
                    modelResult.code = -1;
                    modelResult.message = "缺少timestamp参数!";
                    JsonResult json = new JsonResult(modelResult);
                    context.Result = json;
                }
                else
                {
                    string appid = context.HttpContext.Request.Headers["appid"];
                    string sign = context.HttpContext.Request.Headers["sign"];
                    string timestamp = context.HttpContext.Request.Headers["timestamp"];
                    DateTime requestTime = DateTimeHelper.GetTime(timestamp);
                    // 接口过期
                    int apiExpiry = 20;
                    if (requestTime.AddSeconds(apiExpiry) < DateTime.Now)
                    {
                        modelResult.code = -3;
                        modelResult.message = "接口过期!";
                        JsonResult json = new JsonResult(modelResult);
                        context.Result = json;
                    }
                    else
                    {
                        //从数据库或缓存查找对应的appkey,
                        string appkey = "fdsafdsafdsafasdfasdf";
    
                        if (!string.IsNullOrEmpty(appkey))
                        {
                            modelResult.code = -4;
                            modelResult.message = "appid不存在!";
                            JsonResult json = new JsonResult(modelResult);
                            context.Result = json;
                            return;
                        }
                        //是否合法判断
                        SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
                        sortedDictionary.Add("appid", appid);
                        sortedDictionary.Add("timestamp", timestamp);
                        //获取post数据,并排序
                        Stream stream = context.HttpContext.Request.Body;
                        byte[] buffer = new byte[context.HttpContext.Request.ContentLength.Value];
                        stream.Read(buffer, 0, buffer.Length);
                        string content = Encoding.UTF8.GetString(buffer);
                        context.HttpContext.Request.Body = new MemoryStream(buffer);
                        if (!String.IsNullOrEmpty(content))
                        {
                            string postdata = System.Web.HttpUtility.UrlDecode(content);
                            string[] posts = postdata.Split(new char[] { '&' });
                            foreach (var item in posts)
                            {
                                string[] post = item.Split(new char[] { '=' });
                                sortedDictionary.Add(post[0], post[1]);
                            }
                        }
                        //拼接参数,并在开头和结尾加上key
                        StringBuilder sb = new StringBuilder(appkey);
                        foreach (var item in sortedDictionary)
                        {
                            sb.Append(item.Key).Append(item.Value);
                        }
                        sb.Append(appkey);
                        if (sign != CryptographyHelper.Md5_Encryption(sb.ToString()))
                        {
                            modelResult.code = -2;
                            modelResult.message = "签名不合法!";
                            JsonResult json = new JsonResult(modelResult);
                            context.Result = json;
                        }
                    }
                }
            }
        }
    }
    View Code

    使用方式

    using Microsoft.AspNetCore.Mvc;
    using test.Filters;
    
    namespace TEST.Controllers
    {
        [TypeFilter(typeof(VerificationFilters))]
        public class HomeController : Controller
        {
            //此接口就使用接口验证过滤器,从控制器上继承下来的        
            public IActionResult Index()
            {
                return Json("aa");
            }
    
            //此接口就使用接口验证过滤器,在action头标记了过滤器,可单独作用于action
            [TypeFilter(typeof(VerificationFilters))]
            public IActionResult Index2()
            {
                return Json("aa");
            }        
        }
    }
    View Code

    调用检证接口示例

    /// <summary>
            /// 
            /// </summary>
            /// <param name="appid">身份码</param>
            /// <param name="appkey">验证码</param>
            /// <param name="timestamp">时间</param>
            /// <param name="role">角色</param>
            /// <param name="identity">设备码</param>
            /// <param name="version">版本</param>
            /// <param name="data">数据</param>
            /// <returns></returns>
            [HttpPost]
            public IActionResult api(string appid, string appkey, int timestamp, int role, int identity, string version, string data)
            {
                if (timestamp == 0)
                {
                    timestamp = DateTimeHelper.ConvertDateTimeInt(DateTime.Now);
                }
                SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
                sortedDictionary.Add("appid", appid);
                sortedDictionary.Add("timestamp", timestamp.ToString());
                sortedDictionary.Add("role", role.ToString());
                sortedDictionary.Add("identity", identity.ToString());
                sortedDictionary.Add("version", version);
                string val = "";
                try
                {
                    string[] dataitem = data.Split("
    ");
                    foreach (var item in dataitem)
                    {
                        string[] tmp = item.Split('=');
                        sortedDictionary.Add(tmp[0], tmp[1]);
                    }
                }
                catch (Exception)
                {
                    val = "data数据格式有问题!";
                    ViewBag.Data = val;
                    return View();
                }
                StringBuilder sb = new StringBuilder(appkey);
                foreach (var p in sortedDictionary)
                    sb.Append(p.Key).Append(p.Value);
                sb.Append(appkey);
                string sign = CryptographyHelper.Md5_Encryption(sb.ToString());
                val = $" appid:{appid}
     sign:{sign}
     timestamp:{timestamp}
     {data}";
                ViewBag.Data = val;
                return View();
            }
    View Code

     源码下载地址  https://files.cnblogs.com/files/fengmazi/test.rar

    技术在于分享,大家共同进步

  • 相关阅读:
    U8 UAP 存储过程未提供该参数
    SQL exec 报错 找不到存储过程 'select * from TEMP_byhktb20191213104416697'
    U8修改存货扩展自定义项
    插入临时表时报在将 nvarchar 值 'config_category.metadata_item.popedom' 转换成数据类型 int 时失败
    拼接字符串发生的错误
    js 三种提取部分字符串的方法的 区别: slice(start, end) substring(start, end) substr(start, length)
    sqlserver 保留位数
    1月转01月
    焦点图插件-06
    通栏自适应通栏焦点图-05
  • 原文地址:https://www.cnblogs.com/fengmazi/p/8337071.html
Copyright © 2011-2022 走看看