安全的API接口解决方案

在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优

在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对于公开访问的接口,专业点的都会做下安全验证,数据签名之类

反而现在,谁都可以用WEB API估接口,安全性早忘一边了,特别是外包小公司的APP项目,80%都有安全漏洞(面试了大半年APP开发得出的结论)

特在过年之前,整理了下在用的解决方案,本方案解决了

  • 数据安全问题
  • 标准消息结构
  • 接口测试程序
  • 接口文档体现


正文

数据结构

对于一个接口,返回的内容除了要返回业务数据外,还得返回处理状态,并且这个状态是在每个接口都得有

所以数据格式都会定义为:

数据头(描述数据信息)

-----------------------------------

数据体(具体数据)

本文定义结构为

/// <summary>
    /// 处理结果
    /// </summary>
    public class DealResult
    {
        /// <summary>
        /// 处理结果
        /// </summary>
        public bool Result
        {
            get;
            set;
        }
        /// <summary>
        /// 消息
        /// </summary>
        public string Message
        {
            get;
            set;
        }
        /// <summary>
        /// 关联数据
        /// </summary>
        public object Data
        {
            get;
            set;
        }
    }

所有接口都返回此对象,会描述本次请求的状态,和对应的数据,服务端则根据实际情况,返回处理结果和对应的数据

数据安全

开方式接口安全性就不用多说了,解决方法为加密,或数据签名验证,本文方案为进行数据签名

同返回的数据一样,提交到服务器的数据格式也统一约定,定义一个数据头基类

    /// <summary>
    /// 参数基类
    /// </summary>
    [Serializable]
    public class ParameBase
    {
        string time = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
        /// <summary>
        /// 时间 格式 yyyy-MM-dd hh:mm:ss
        /// </summary>
        public string Time
        {
            get
            {
                return time;
            }
            set
            {
                time = value;
            }
        }
        /// <summary>
        /// 来源网站 = 1, IOS = 2,Android = 3, 微信 = 4
        /// </summary>
        public int SourceFrom
        {
            get;
            set;
        }
        /// <summary>
        /// 签名
        /// </summary>
        public string Token
        {
            get;
            set;
        }

    }

一个登录对象表示为

    /// <summary>
    /// 登录
    /// </summary>
    public class Login : ParameBase
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string Name
        {
            get;
            set;
        }
        /// <summary>
        /// 密码
        /// </summary>
        public string Password
        {
            get;
            set;
        }
    }

数据签名表示为(KEY稍后讲到)

Token=MD5(属性值1+值2....+KEY)

按此对象表示为 MD5(Name+PassWord+Source+Time+KEY)

如果是GET参数怎么办,一样,按参数名计算,同时传递的参数要附带上Source,Time,Token

密钥机制

有的喜欢把密钥放在客户端,或固定密钥,显然都有安全问题,解决方法是动态获取

这就意味着在设计接口时,有一个接口是首先要调用的,让服务器返回密钥,于是就有了登录的概念

过程表示为

登录>返回用户信息和密钥=>存储用户信息和密钥=>使用密钥调用其它接口

这样只有登录者和服务器才知道自已的密钥了

综上所述,数据结构表示为

客户端提交结构为 ParameBase(附带签名信息)

服务端返回结构为 DealResult

登录机制

同网页请求一样,怎么知道多次调用是同一个人呢,这里采用了COOKIE的形式,登录后服务端返回一个COOKIE,客户端再请求时带上这个COOKIE

服务端需要存储这个COOKIE标识,所有的验证处理都会基于此标识来判断用户

有了上面基础,进入项目阶段

WEB API项目

其实用什么项目类型都行,只是WEB API方便了对象结构序列化和传参

默认WEB API路由RESUFUL形式,没有控制器方法,只能按METHOD来定义,很不方便,改成控制器的形式,这样就能用方法名来访问了

更改路由配置为

?


1

2

3

4

5

config.Routes.MapHttpRoute(

                name: "DefaultApi",

                routeTemplate: "api/{controller}/{action}/{id}",//加上路由ACTION参数

                defaults: new { id = RouteParameter.Optional }

            );

在此文,数据分为请求和返回,以登录返回用户信息为例,登录为请求,用户信息为返回,示例对象结构为

用户对象

/// <summary>
    /// 登录返回用户
    /// </summary>
    public class User
    {
        /// <summary>
        /// 用户编号
        /// </summary>
        public int Id
        {
            get;
            set;
        }
        /// <summary>
        /// 名称
        /// </summary>
        public string Name
        {
            get;
            set;
        }
        /// <summary>
        /// 本次登录的KEY
        /// </summary>
        public string Key
        {
            get;
            set;
        }
        /// <summary>
        /// 本资登录的凭证
        /// </summary>
        public string Voucher
        {
            get;
            set;
        }

    }

请求方式

这里只采用了GET,POST两种方式,根据实际情况定义,控制器方法一定需要都标明,不然会出现路由BUG

定义登录方法

/// <summary>
        /// 登录
        /// </summary>
        /// <param name="parame"></param>
        /// <returns>User</returns>
        [HttpPost]
        [AnonymousSign]
        public DealResult Login([FromBody] Login parame)
        {
            if (parame.Password != "123")
            {
                return DealResult(false, "密码不正确");
            }
            string key2 = System.Guid.NewGuid().ToString();
            string voucher = System.Guid.NewGuid().ToString();
            var user = new User() { Name = parame.Name, Id = 1, Key = key2, Voucher = voucher };
            var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//保存客户端和服务端时间差
            LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);
            CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE
            return DealResult(true, "", user);
        }

这里可以看到,创建了两个GUID,一个为用户凭证,一个为用户密钥,放入用户信息返回,同时调用LoginStatusContext.SetLoginStatus保存登录信息

同时使用了AnonymousSign标注,此方法使用默认签名Setting.DefaultKey

定义获取用信息方法

        /// <summary>
        /// 基本信息
        /// </summary>
        /// <param name="name">参数name</param>
        /// <returns>User</returns>
        [HttpGet]
        public DealResult GetBasicInfo(string name)
        {
            var user = new User() { Name = name, Id = CurrentUserId };
            return DealResult(true, string.Empty, user);
        }

示例控制器完整定义

 /// <summary>
    /// 帐号操作
    /// </summary>
    [SignCheckAttribute]
    public class AccountController : BaseController
    {
        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="parame"></param>
        /// <returns>User</returns>
        [HttpPost]
        [AnonymousSign]
        public DealResult Login([FromBody] Login parame)
        {
            if (parame.Password != "123")
            {
                return DealResult(false, "密码不正确");
            }
            string key2 = System.Guid.NewGuid().ToString();
            string voucher = System.Guid.NewGuid().ToString();
            var user = new User() { Name = parame.Name, Id = 1, Key = key2, Voucher = voucher };
            var timeDiff = (DateTime.Now - Convert.ToDateTime(parame.Time)).TotalSeconds;//保存客户端和服务端时间差
            LoginStatusContext.SetLoginStatus(voucher, user.Id, key2, timeDiff);
            CoreHelper.CookieHelper.AddCookies("user", voucher);//存入COOKIE
            return DealResult(true, "", user);
        }

        /// <summary>
        /// 基本信息
        /// </summary>
        /// <param name="name">参数name</param>
        /// <returns>User</returns>
        [HttpGet]
        public DealResult GetBasicInfo(string name)
        {
            var user = new User() { Name = name, Id = CurrentUserId };
            return DealResult(true, string.Empty, user);
        }

        /// <summary>
        /// 测试异常
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public DealResult TestException()
        {
            int a = 0;
            var b = 10 / a;
            return DealResult(true);
        }

    }

此控制器标注了SignCheckAttribute用以进行签名判断

具体实现可看SignCheckAttribute代码

SignCheckAttribute里实现了有

  • 数据签名判断
  • 签名超时判断
  • 用户登录限制
  • 签名重复使用处理(一个签名只能使用一次)
  • 过期登录用户处理(没有主动退出用户清理)

为了统一处理异常,配置了异常处理

?


1

GlobalConfiguration.Configuration.Filters.Add(new ExceptionAttribute());

对接口进行测试

大杀器来了,配合此方案放出了对应的测试工具,虽然WEB API有个扩展,但没法对此方案测试

使用此工具能方便按方案要求调用接口,为了方便参数拼接,POST和GET都采用URL参数的形式输入

测试登录/api/account/login

测试获取信息/api/account/GetBasicInfo

测试异常处理/api/account/TestException

在未登录情况下调用获取信息

接口文档

接口结构文档一直是很让人头疼的事,手写更改了又得维护,版本不一样还麻烦,自动生成最好了,同样WEB API 带扩展没法表示此结构详细

大杀器2号来了,按代码注释动态生成接口文档,文档格式与控制器保持一致

Home控制器代码实现

    public ActionResult Index(SummaryAnalysis.ExportType exportType = SummaryAnalysis.ExportType.NONE)
        {
            if (exportType != SummaryAnalysis.ExportType.NONE)
            {
                var str = SummaryAnalysis.Load(exportType);
                return File(str, "application/octet-stream", "Model_" + exportType + ".zip");
            }
            else
            {
                if (string.IsNullOrEmpty(outPut))
                {
                    outPut = SummaryAnalysis.Load(exportType);
                }
                ViewBag.OutPut = outPut;
                return View();
            }
        }
    }

在见过的开发文档,我觉得这是最好的展现形式了,还有锚点,快速定位到对象结构,并且与源代码保持一致

附WEB API 自带文档生成区别

附上项目源码

http://pan.baidu.com/s/1c2rDacK

项目结构:

----------WPF测试程序

----------接口示例

虽然跟CRL快速开发框架无关,但还是加上CRL的名,好文要顶!

时间: 2024-12-15 01:39:05

安全的API接口解决方案的相关文章

【转】整套完整安全的API接口解决方案

原文地址:http://www.cnblogs.com/hubro/p/6248353.html 在各种手机APP泛滥的现在,背后都有同样泛滥的API接口在支撑,其中鱼龙混杂,直接裸奔的WEB API大量存在,安全性令人堪优 在以前WEB API概念没有很普及的时候,都采用自已定义的接口和结构,对于公开访问的接口,专业点的都会做下安全验证,数据签名之类 反而现在,谁都可以用WEB API估接口,安全性早忘一边了,特别是外包小公司的APP项目,80%都有安全漏洞(面试了大半年APP开发得出的结论)

前后端开发过程中API接口管理有哪些痛点?附几种解决方案

一.API管理的痛点 API接口在设计时往往需要编写大量的文档,而且编写完成之后还会经常改动,文档编写维护工作量大. 接口文档编写好后,实际的代码可能会与文档有出入,这个时候文档是不准确的,文档与代码保持修改同步也是一个很大的工作量.随着接口版本的迭代,接口文档需要同步更新.有些时候接口会成为对接双方的开发进度瓶颈,因为接口调用会有依赖,类似app的项目,前端会需要调用后端接口,接口功能不实现会影响前端开发进度.接口开发完以后,做接口测试不方便,特别是接口数量多,参数复杂的情况,测试工作量大.接

电商平台适用基础快递查询api接口对接demo解决方案

电商企业从接收订单-配货-打印快递单到后期的快递员收件-快递配送-轨迹查询-签收短信通知等,都需要快递接口的接入.整理目前可以实现如上服务的有 1.各家快递公司:提供快递查询.电子面单打印等2.快递100:提供在线寄件.快递查询等3.菜鸟:提供快递查询.电子面单打印等4.快递鸟:提供预约寄件.快递查询.电子面单打印.代收货款.短信服务等 各家快递公司提供的是一级接口,快递100.菜鸟和快递鸟是集成接口,对于使用快递比较多的企业来说,集成接口相对更好维护一些.所以一般电商都会选择集成的接口.快递鸟

CDIF灵长科技 API 管理解决方案技术白皮书

灵长科技 API 管理解决方案的核心技术是具备中美知识产权保护的,名为通用设备互联框架(CDIF:common device interconnect framework)的软件框架,目前有部分开源实现存放在:https://github.com/out4b/cdif(注:开源部分遵守相关开源代码许可协议).CDIF 是世界上第一种基于 REST 和 JSON 的 SOA软件框架,提供了与基于XML 的 WSDL 语言和 SOAP 协议同等抽象能力.但简洁得多的基于JSON 的实现,也非常适合用

如何让你的 Asp.Net Web Api 接口,拥抱支持跨域访问。

由于 web api 项目通常是被做成了一个独立站点,来提供数据,在做web api 项目的时候,不免前端会遇到跨域访问接口的问题. 刚开始没做任何处理,用jsonp的方式调用 web api 接口,总是报一个错误,如下: 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的: {"YourSignature":"嫁人要嫁程序员,钱多话少死得早"} 然而,JSONP请求期望得到这样的JSON

云脉推出表格识别API接口可以自助接入

针对如今市场上对于海量票据信息的录入需求,近期厦门云脉技术有限公司推出票据识别相关的产品与服务,更是在云脉OCR SDK开发者平台上上线表格识别API接口,供广大开发者和集成商自助接入.为了降低财务系统的开发成本,帮助更多的财务系统进行技术创新升级,厦门云脉在重磅推出票据识别SDK时,同时也在云脉OCR SDK开发者平台( www.yunmaiocr.com)上开放表格识别API接口. 通过以SaaS模式来提供票据识别技术,从线下嵌入SDK模式获得表格识别功能到直接接入API,从线下识别到云识别

HTTP API接口安全设计

HTTP API接口安全设计 API接口调用方式 HTTP + 请求签名机制   HTTP + 参数签名机制 HTTPS + 访问令牌机制 有没有更好的方案? OAuth授权机制 OAuth2.0服务的几种授权流程 ----------------------------------------------------------------------------------------------------------------------------------------------

智能识别快递地址api接口实现(PHP示例)

电商.ERP等行业发货时,批量录入图片上的收件人地址是个难题:智能识别收件人API是近乎完美的解决方案,通过识别图片,解析出图片中收件人的姓名.电话.详细地址(省.市.区/县.详细地址).将此接口集成到下单环节,可极大的提高了发货效率. 一.使用场景 场景1:客户微信(或QQ.钉钉等)截图收件人信息及地址 场景2:快递单上面的收件人信息及地址 场景3:手写收件人信息及地址 二.智能识别收件人服务使用流程 1.注册快宝开放平台,获取开发者账号,并认证资质:http://open.kuaidihel

ASP.NET Core 实战:构建带有版本控制的 API 接口

 一.前言 在上一篇的文章中,主要是搭建了我们的开发环境,同时创建了我们的项目模板框架.在整个前后端分离的项目中,后端的 API 接口至关重要,它是前端与后端之间进行沟通的媒介,如何构建一个 “好用” 的 API 接口,是需要我们后端人员好好思考的. 在系统迭代的整个过程中,不可避免的会添加新的资源,或是修改现有的资源,后端接口作为暴露给外界的服务,变动的越小,对服务的使用方造成的印象就越小,因此,如何对我们的 API 接口进行合适的版本控制,我们势必需要首先考虑. 系列目录地址:ASP.NET