百家饭平台作为一个OpenAPI的编辑、测试、代码生成的工具,写了这么多文章,还没有真正介绍过OpenAPI这个标准,正好vuepress写的差不多了。今天就以这个为选题,开始这个月的写作。如果没有特殊声明,介绍的OpenAPI标准以v3.1.0版本为主。

这个月陆续接到多个API网关的需求,百家饭平台也开始扩展原来的网关功能,向企业级API网关挺进,其中,有需求提到对多种API认证方式的需求,那我们就来介绍一下API常用的认证手段和OpenAPI写进标准的都有哪些。

HTTP Basic认证(OpenAPI包含)

Basic认证的基本方法是在头部附加包含用户名和密码的认证信息,形态如下:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

根据标准(rfc2617)的说明,内容部分的Basic表明这一认证手段是HTTP Basic的认知方式,而后面空格后面的内容是base64加密之后的用户id,:号,密码拼接好的字符串,用伪代码说,也就是

base64(userid+":"+password)

该模式在中间有Proxy存在的时候,存在server和proxy之间的附加交互。

有些语言的http类库都提供直接设置basic认知的函数,比如golang的http.Request类提供BasicAuth来获取认知信息,以及SetBasicAuth用于设置认知信息。(Java搜索了一下好像没有,参考头部信息的设置流程获取即可)。

安全点评

从上面的说明可以看出,这个安全方式的问题是比较明显的,用户名密码虽然经过了base64编码,但是由于base64随意可解,这就导致用户名密码很容易被破解。

因此,使用上述认知手段,建议:

1)一定不要用http,要用https(防止网络监听)

2)考虑对用户名,密码进行加密,不要直接传输用户名、密码,改为传输经SHA1、HMAC等加密方式加密的密文

OpenAPI定义方式

      type: http
      scheme: basic

Bearer认证

bearer百度了一下,翻译过来是持票人(什么鬼?,就是跑腿的呗),和Basic认证一样,使用了头部的Authorization用来存储认证信息,但是改为:

Authorization: Bearer QWxhZGRpbjpvcGVuIHNlc2FtZQ==

跑腿认证,来源于OAuth2,有标准RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage (rfc-editor.org)

基本的意思就是服务器在认证了一个用户是有效的之后(比如通过登录接口),在header中附加一个自己加密的信息给回到客户端,客户端拿到这个信息之后,可以在后续调用中附加这一字段,用于加密接口的认证。注意,上面的例子虽然是base64字符串,但是Bearer认证并不要求一定使用base64,实际更多可能是HEX编码的16进制字符串。

这里还要提到,常说的JWT认证实质是Bearer认证的一种,只不过JWT认证明确提到服务器加密的信息应该是JSON的。

安全点评

  1. 仅可用于HTTPS,还是有泄露问题
  2. 建议加密的信息中包含时间戳,这样可以基于时间戳做时长控制

这种方式如果是简单的要求调用前获取TOKEN,并不太适用API系统,API系统不应该存在前置的这个认证获取调用过程,所以才有OAuth那套时间控制机制(刷新/重新获取)作为补充。

OpenAPI定义方式

      type: http
      scheme: bearer
      bearerFormat: JWT //如果是JWT可附加该信息,该信息对客户端意义不大,客户端只能获得加密数据

API Key认证

API Key认证方式比较简单,就是在Header、Query或者Cookie中附加特定的访问Key即可,如果你愿意,放在Url Path中都行。

但是这只是一种通用的描述,这种模式描述的范围比较广泛,其内部应该可以分为多种子模式。

附加明文Key

服务器分配一个key给调用方,调用方直接附加这个值用于认证。这种方式简单粗暴,一旦泄露,即可被重复使用,等同于Basic认证。

附加服务器可解密的密文信息

等同于Bearer认证,服务器先生成一个Token再交予客户端,如果使用了Cookie作为存储,其实就是一般的客户端登录机制了。

附加按一定规则生成的密文

在常见的企业对企业的API认证中,经常出现的认证方式,要求客户端根据提交的某个关键信息、实现分配的客户端ID,通常还有时间戳,基于一定的组合方式提交一个MD5或其他算法生成的一串密文。

最常见的就是各种md5,md5一般带secret加请求信息,比如加入一个sign参数,取值为

sign = md5(arg1+'+'+arg2+'+'+timestamp+'+'+secret)

再把userid、sign和明文的arg1、arg2和时间戳一起传给服务器,服务器拿出该user的secret后再拼接出这个sign,比较之后就算通过。(上面字符串形态的+用于避免其中有空内容的情况)

OpenAPI定义方式

apiKey:
      type: apiKey
      in: header
      name: X-API-KEY

上面定义了一个在header中的名为 X-API-KEY的apiKey,OpenAPI虽然完成了字段的定义,但是对字段内容如何生成,并没有相应的标准化方式,这块是OpenAPI没有覆盖到的地方(百家饭提供了公式化参数用于说明如何计算获得key)。

Oauth2认证

Oauth2是10年代,各大主流网站设计第三方应用时设计的一套鉴权机制,核心是通过设计一套独立于用户密码,由登陆后用户生成的密钥以及对应的应用获取、刷新、重置等机制构建的第三方应用登录机制。

打个比分,原来用于必须本人拿信用卡去商家买东西,现在要支持一个小弟去买,那用户从商家拿到一个令牌,发给一个小弟,这个小弟拿着这个令牌就可以代替用户去商家取货,但是这个令牌不是一直有效的,每隔一段小时间要去刷新一下,要是小时间不刷新就要在一个大时间周期里去重新获取。

Oauth2在发展过程中又细分出很多中细的方案,试图覆盖更多的使用场景,上面讲的这个例子是其中的Authorization code模式,另外还有:

  • Implicit:简单版Authorization code,不能刷新,只能通过浏览器维持登录。类似用户和小弟都去商场,用户坐沙发上不动弹,小弟到处跑,但是卖家随时可以通过示意用户去获得同意。
  • Resource owner password credentials (or just password) – 等同于直接把用户在信用卡密码给小弟
  • Client Credentials :小弟有自己的附属卡

感觉后面两种说了跟没说差不多……

OpenAPI定义方式

      type: oauth2
      description: 
      flows: //定义oauth2的流程类型和适用的范围
        implicit:  
          authorizationUrl: https://api.example.com/oauth2/authorize
          scopes:
            read_pets: read your pets
            write_pets: modify pets in your account

认证总结

经过这一调研,总结如下表,我们建议Basic就最好别用了,Bearer以及Oauth2看场景,如果你是要给第三方应用开放数据,可以使用。如果你是一个API提供方,面向的对象多是其他企业的下游服务,我建议还是使用复杂API Key认证模式。

存储于HTTP Authorization存储于其他位置附加其他过程控制机制应用建议
提交明文HTTP Basic认证简单API Key认证最好不要用
提交由服务器加密和解密的密文HTTP Bearer认证带状态控制的API Key认证Oauth2用于第三方应用场景
提交客户端加密,由服务器根据内容可验证的密文复杂API Key认证用于服务器对服务器场景

而对于OpenAPI来说,OpenAPI基本已经涵盖了接口常用的三种认证方式的定义,从说明一个API的角度还是够了,下一步需要加强的是生成方式等的定义。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐