使用过滤器对mvc api接口安全加密

2021-02-18 17:16

阅读:392

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  
     */

    /// 
    /// api接口加密身份验证过滤器
    /// 
    public class VerificationFilters : IAuthorizationFilter
    {
        /// 
        /// 接口签名验证
        /// 
        /// 
        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;
                    }
                    //是否合法判断
                    SortedDictionarystring, string> sortedDictionary = new SortedDictionarystring, 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

调用检证接口示例

技术分享图片技术分享图片
/// 
        /// 
        /// 
        /// 身份码
        /// 验证码
        /// 时间
        /// 角色
        /// 设备码
        /// 版本
        /// 数据
        /// 
        [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);
            }
            SortedDictionarystring, string> sortedDictionary = new SortedDictionarystring, 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("\r\n");
                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}\r\n sign:{sign}\r\n timestamp:{timestamp}\r\n {data}";
            ViewBag.Data = val;
            return View();
        }
View Code

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

 

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

 


评论


亲,登录后才可以留言!