关于开放平台的接口安全性

intro

互联网时代,服务型企业将自己的功能服务封装成一系列API(Application Programming Interface,应用编程接口)开放出去,供第三方开发者使用,正成为一种趋势,所开放的API也就是大家熟悉的OpenAPI。

之前有写过一篇关于接口的文章,接口的定义其实就是:软件接口是用于两个模块间交互的共享数据边界,它提供:常量定义,数据类型及结构定义,方法描述及异常指定。

进程内部接口调用和机构内部跨系统的调用,因为基本在一个局域网内,相对是安全的,一般不太会考虑到安全方面的内容。

而开放平台则属于跨机构的接口调用了,这里我们主要探讨下在开放平台下的接口调用安全性问题。而关于开放平台本身的接口设计与建设过程不在本文中阐述了!

why?

因为跨机构或者说基于互联网的接口调用,在物理上报文内容需要经过多个设备中转,这其中便存在被伪造、窃听、劫持和篡改的可能!
如何确保接口的安全传输和信息的准确传递是对接口设计者和开放平台建设者的一种考验!

what?

追根溯源,其实关于接口安全的本质,即什么样的接口是安全的?可以总结为以下三点:

  1. 避免监听风险,接口内容不能被他人知晓
    因为有中间设备的路由,存在被监听的可能,但我们希望接口内容不被第三方知道!
  2. 避免伪造风险,接口的发送者身份确认
    即认证(Authentication)接受者需要确认到底是谁发的消息,发送者需要表明自己的身份
  3. 避免篡改风险,接口内容没有被篡改过
    接收者接收到的接口内容需要确保是发送者发送的,需确保不曾被中间渠道修改过

how?

那如何做到开放平台的接口调用安全呢?

从非技术层面出发,由以上几点我们可以知道,影响接口和消息传递安全的其实是中间层!
最有效直接的沟通当然是面对面的沟通,加入了中间媒介就增加了沟通的成本和安全的风险。
拉专线便是最直接有效的方式,也是目前很多大机构间接口调用普遍采用的方式!
但拉专线的做法并不是真正开放的、互联网的做法,而且拉专线本身是有业务费用的,而程序员很多时候的主要作用和任务就是要减少业务费用

那接下来我们就正式进入正题,探讨一下如何从技术层面实现开放平台的接口调用安全。

知识储备

正式开始前,稍微回顾下安全相关的一些术语和定义:

  • 编解码(base64)
    encode&decode,没有秘钥的参与
  • 摘要算法(md5,sha1,sha256)
    单向不可逆
  • 对称加解密(des,3des,aes)
    双方约定公共秘钥,加解密速度相对较快
  • 非对称加解密(rsa)
    公钥加密,私钥解密,加解密速度相对较慢
  • 数字签名和证书(sha256rsa)
    私钥加签,公钥验签
    签名为摘要+非对称加密
    证书则通过再增加一个CA中心,公开认证签名的来源及合法性

方案调研

  • 避免窃听风险
    在开放的公网传输,窃听其实是无法避免的,我们能做的就是即使被窃听了,你也拿不到真正有效的信息,简而言之就是要保证接口报文不能以明文的方式在网络上传输! 实现时需要考虑密钥的交换和传输时的报文加解密!
    SSL/TLS就是为此而生的!协议本身的实现也很精妙,结合了非对称加密和对称加密的过程,握手阶段采用非对称加解密协商会话密钥,传输阶段采用对称加解密传输报文。
    参考文档:
    http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
  • 避免伪造风险
    需要能够识别出发送者的身份,即需要一个认证(Authentication)的过程,基于http协议的认证方式大致有basic,digest,api-key,oauth2等等。
    参考文档:
    http://www.cnblogs.com/Irving/p/4964489.html
  • 避免篡改风险 思路是发送者对接口的全部内容(有些实现是对部分重要字段,并不安全也增加了实现复杂度,不推荐)形成校验和,接收者同样对收到的接口全部内容计算校验和并与接收到的校验和做比对,一致则认为接口未被篡改!
    身份证和卡号的最后一位其实都是校验和算法或者摘要算法在我们身边的实际应用!
    参考文档:
    https://zh.wikipedia.org/wiki/校验和

可以看到,数字签名算法(签名过程简介:对全报文进行摘要后,再用表明身份的私钥进行非对称加密,一般为Sha256WithRSA)其实是综合了以上的第二点(避免伪造风险)和第三点(避免篡改风险)!
参考资料:
http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html

方案设计

开放平台的接口调用,一般要求语言无关性,https协议成为传输层协议首选,而json以其简洁、直观、小巧基本成为报文协议的首选。其他在金融领域应用较多的有在tcp/ip传输协议之上的8583报文协议,swift的MXs报文协议等,接触过这些协议的开发者大多被其晦涩难懂、各种弯弯绕折磨的痛苦不堪~

但基于https+json的开放平台搭建又分两种方式,笔者将其划分为以下两类:

  • gateful型
    提供固定网关端点endpoint,统一采用POST方法进行接口调用,报文中包含交易标识代码transcode字段
  • restful型
    以endpoint代表资源标识,以get/post/put/delete等http method代表对资源的增删改查等操作,requestParam及requestBody中一般不再包含交易标识字段,实际上可以理解为transcode=endpoint+method

机构对机构:

建议采用gateful,restful设计刚出来的时候,几乎所有人都拥抱了起来,现在说到OpenAPI,如果你不知道restful,感觉会被人笑话觉得low!
但如果你细想一下就会发现restful的设计在接口安全的实现上就会很难!难点主要在对全接口内容的摘要计算上,对于restful设计,http method及endpoint都应属于接口内容的一部分!我们可以看到有很多restful类型的开放平台的待签名源串的选取方案是:
Http Method+Endpoint+RequestParam的key=value方式,这里RequestBody成了最大的问题,几乎所有的基于restful设计的签名方案里都忘了RequestBody的存在,不是他们忘了,是他们实在不知道如何处理RequestBody

机构对个人:

建议采用restful,主要原因是机构对个人很难做到双向签名,不可能在每个用户的手机或电脑终端上存放私钥(当然有很多程序是拿电脑的mac地址或者手机的IMEI号码作为客户端标识),也不可能在机构端存放所有用户的公钥。
这里一般是忽略了报文的篡改风险的,但篡改难度因为https的存在加大了很多,报文的内容因为是加密的,在不知道会话密钥的情况下,成功修改报文内容的可能微乎其微(而且http协议本身也有content-length的header,起到了一定的摘要作用)。

总结

一句话总结开放平台的安全方案设计就是:
https是必须,机构对机构建议采用数字签名或证书,机构对个人采用认证即可!

案例参考

笔者调研了诸多的开放平台,不得不说的是,很多开放平台的接口安全设计是有瑕疵的:要么很不友好,让对接开发者很头大;要么是存在一定安全隐患的。反例就不列举了!
这里我们选取几个笔者觉得很不错的开放平台案例,供大家参考学习!

机构对机构

机构对个人