使用过滤器对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;
                    }
                }
            }
        }
    }
}

使用方式

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");
        }
    }
}

调用检证接口示例

/// <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("\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();
        }

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

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

原文地址:https://www.cnblogs.com/fengmazi/p/8337071.html

时间: 2024-08-03 13:15:56

使用过滤器对mvc api接口安全加密的相关文章

Swagger UI教程 API 文档神器 搭配Node使用 web api 接口文档 mvc接口文档

两种方案 一.Swagger 配置 web Api 接口文档美化 二.通过NodeJS 发布Swagger UI 配置api 文档 先说一下简单的 Swagger 配置 web Api  Swagger-UI本身只提供在线测试功能,要集成它还需要告诉它本项目提供的各种服务和参数信息.这里就需要一些工作量了,不过好在许多第三方库已经给我们完成了这一工作.我这里用的是Swashbuckle,使用它也比较简单,直接使用Nuget添加其程序包即可: 1.初始化包  PM> Install-Package

如何写出安全的API接口(参数加密+超时处理+私钥验证+Https)

原文:http://www.cnblogs.com/codeon/p/6123863.html#3580351 1.完全开放的接口 有没有这样的接口,谁都可以调用,谁都可以访问,不受时间空间限制,只要能连上互联网就能调用,毫无安全可言. 实话说,这样的接口我们天天都在接触,你查快递,你查天气预报,你查飞机,火车班次等,这些都是有公共的接口. 我把这称之为裸奔时代.代码如下: /// <summary> /// 接口对外公开 /// </summary> /// <return

微信小程序的Web API接口设计及常见接口实现

微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,通过小程序的请求Web API 平台获取JSON数据后,可以在小程序界面上进行数据的动态展示.在数据的关键 一环中,我们设计和编写Web API平台是非常重要的,通过这个我们可以实现数据的集中控制和管理,本篇随笔介绍基于Asp.NET MVC的Web API接口层的设计和常见接口代码的展示,以便展示我们常规Web API接口层的接口代码设计.参数的处理等内容. 1.Web API整体性的架构设计 我们整体性的架构设计

Restful风格API接口开发springMVC篇

Restful风格的API是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制. 在Restful风格中,用户请求的url使用同一个url而用请求方式:get,post,delete,put...等方式对请求的处理方法进行区分,这样可以在前后台分离式的开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口. 在Restful风格中,现

聊聊 PHP 与手机 APP 开发(API 接口开发)

对于新手开发api接口的一探讨 一.先简单回答两个问题: 1.PHP 可以开发客户端?答:不可以,因为PHP是脚本语言,是负责完成 B/S架构 或 C/S架构 的S部分,即:服务端的开发.(别去纠结 GTK.WinBinder) 2.为什么选择 PHP 作为开发服务端的首选?答:跨平台(可以运行在UNIX.LINUX.WINDOWS.Mac OS下).低消耗(PHP消耗相当少的系统资源).运行效率高(相对而言).MySQL的完美搭档,本身是免费开源的,...... 二.如何使用 PHP 开发 A

Winform混合式开发框架访问Web API接口的处理

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 在我的混合式开发框架里面,集成了WebAPI的访问,这种访问方式不仅可以实现简便的数据交换,而且可以在多种平台上进行接入,如Winform程序.Web网站.移动端APP等多种接入方式,Web API的处理方式和微信提供的接口处理规则类似,也是通

php开发api接口

做过 API 的人应该了解,其实开发 API 比开发 WEB 更简洁,但可能逻辑更复杂,因为 API 其实就是数据输出,不用呈现页面,所以也就不存在 MVC(API 只有 M 和 C),那么我们来探讨下,如何使用php进行手机API接口开发 一.先简单回答两个问题: 1.PHP 可以开发客户端? 答:可以,因为PHP是脚本语言,是负责完成 B/S架构 或 C/S架构 的S部分,即:主要用于服务端的开发.但是,PHP可不仅仅只能在互联网站上发展,一个PHP for Android(PFA)站点表示

浅谈使用 PHP 进行手机 APP 开发(API 接口开发)

做过 API 的人应该了解,其实开发 API 比开发 WEB 更简洁,但可能逻辑更复杂,因为 API 其实就是数据输出,不用呈现页面,所以也就不存在 MVC(API 只有 M 和 C),那么我们来探讨下,如何使用php进行手机API接口开发 一.先简单回答两个问题: 1.PHP 可以开发客户端? 答:可以,因为PHP是脚本语言,是负责完成 B/S架构 或 C/S架构 的S部分,即:主要用于服务端的开发.但是,PHP可不仅仅只能在互联网站上发展,一个PHP for Android(PFA)站点表示

API接口幂等性框架设计

表单重复提价问题 rpc远程调用时候 发生网络延迟  可能有重试机制 MQ消费者幂等(保证唯一)一样 解决方案: token 令牌 保证唯一的并且是临时的  过一段时间失效 分布式: redis+token 注意在getToken() 这种方法代码一定要上锁  保证只有一个线程执行  否则会造成token不唯一 步骤 调用接口之前生成对应的 token,存放在redis中 调用接口的时候,将该令牌放到请求头中 (获取请求头中的令牌) 接口获取对应的令牌,如果能够获取该令牌 (将当前令牌删除掉),