RESTful API设计安全性

Posted by Yezhiwei on November 16, 2017

幂等性

幂等性(Idempotent)在这里表示发送一次和多次请求引起的边界效应是一致的。如在网速不够快的情况下,客户端发送一个请求后没有立即得到响应,由于不能确定是否请求是否被成功提交,所以有可能会再次发送另一个相同的请求,幂等性决定了第二个请求是否有效。

HTTP7种方法中的(GET、HEAD和OPTIONS)均是幂等方法。由于DELETE和PATCH请求操作的是现有的某个资源,所以它们是幂等方法。对于PUT请求,只有在对应资源不存在的情况下服务器才会进行添加操作,否则只作修改操作,所以它也是幂等方法。至于最后一种POST,由于它总是进行添加操作,如果服务器接收到两次相同的POST操作,将导致两个相同的资源被创建,所以这是一个非幂等的方法。

怎么解决幂等性问题呢?(简单场景:表单重复提交)利用Redisson实现分布式锁,并防止重复提交。

安全性

微信access_token设计的原理解析

  1. appid:第三方用户唯一凭证。
  2. secret:第三方用户唯一凭证密钥,即appsecret。
  3. access_token:公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。access_token是加密的字符串,其目的是为了接口安全考虑,随便就能调用微信服务器的接口会有很大风险。access_token包含的信息有appid, secret, 用户自定义token,授权url,有效时长等。(登陆后的凭据,证明你已经登陆,相当于你拿着票去看演唱会,才会让你进)。
  4. expires_in:access_token过期时间,因为这里是第三方服务器调用,所以微信服务器必须返回告知给第三方服务器过期时间,从而让第三方服务器更好处理。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
  5. openid:为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,OpenID是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID,开发者可通过OpenID来获取用户基本信息。
  6. unionid:用来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的UnionID是唯一的。换句话说,同一用户,对同一个微信开放平台帐号下的不同应用,UnionID是相同的。

接口调用请求说明

https请求方式:

GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

返回说明

正常情况下,微信会返回下述JSON数据包给公众号:
{"access_token":"ACCESS_TOKEN","expires_in":7200} (access_token的存储至少要保留512个字符空间,expires_in单位是秒,有效期目前为2个小时,即7200秒)
错误时微信会返回错误码等信息,JSON数据包示例如下(该示例为AppID无效错误):
{"errcode":40013,"errmsg":"invalid appid"}

客户端授权

API允许哪些客户端应用程序来调用?

为不同的客户端(iOS、Android、PC等)分配不同的AppKey、AppSecret,方便统计。

只有通过验证的才能继续访问,这一步可以拦截非法的客户端调用。并且这两个参数做为后续接口请求参数的签名参数。

用户授权

当用户通过客户端访问到了私有资源时,判断用户是否有权限访问,是否已经登录过,如果没有登录引导用户去登录,成功后,服务端接口返回access_token,需要授权的接口请求中加上这个参数。

涉及到两个方面问题:

  • 一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证、来路验证——是否通过客户端授权)

  • 一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输、敏感内容加密、数字签名)

是否需要将 request_parameters 也加入到 sign 生成的算法之中?

也不是必须的,仅仅是为了请求的真实性,减少请求的伪造,比如有人抓包拿到 http 请求之后,如果没有验证 sign 这步,那么别人就可以非常简单的修改请求的参数,而请求都会生效。

这里将 request_parameters 也加入到签名之中,就减少了伪造请求的可能性,但是无法杜绝,破坏者可找到我们加密算法的实现,依然可以未知出合法的签名,服务器端永远不能相信客户端的请求都是安全的、合法的。

案例:如用户关系关注接口,如果接口中标识用户用的是数据库的ID,那么在没有参数签名的情况下,可以修改些参数,让很多人关注自己。同时,避免使用数据的自增长的ID作为用户标识,建议使用UUID。

数据获取

避免使用自动增长的id,避免恶意的穷举非法获取信息。

权限(重放攻击)

越权修改用户信息,参数签名。

访问频率限制

在API网关中对接口进行访问频率限制。

有赞云接口文档

理解OAuth 2.0