从resfful API设计到加密算法

Posted 谷子弟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从resfful API设计到加密算法相关的知识,希望对你有一定的参考价值。

众所周知,SOAP 是基于XML的webservice协议,传的数据都是xml格式的,而当下resftul设计比较火,因为快效率高,但是安全性就不及SOAP,

SOAP定义了xml-security的一些规范,除了传数据,还要传额外的安全认证信息。而restful设计没有对安全性规范做什么定义。

那么如何确保Restful设计的安全性呢?

其实不管什么SOA协议,都要面临着安全性问题,也就是客户端和服务器端之间的认证问题,这里顺便扯一下SOA,SOA就是对外提供服务接口的一种思想,可以很多技术实现,什么XML-RPC,RMI,SOAP,Restful等等,(当然前面两种用得很少了)

通常认证有几种情形,

1:常用的用户名密码+认证码登录(登录验证)

2:Cookie + Session

原理即当客户端登录完毕之后,给客户端返回一个 cookie ,服务器端控制该 session 的有效期, 每次请求都带上该值,然后服务器端做验证,退出之后,客户端通知服务端端销毁 session ,自身销毁 cookie 。但是如果抓包获取到 cookie ,就能任意伪造请求了。

危险性高,实际开发估计使用得还不少。

3:基于2的问题,对于CSRF攻击,我们通常会额外生成一个token,放在HttpSession里,每次get/post请求都必须带上这个token,前端JSP通过session.getAttribute("token")就能获取到。如果前后端完全分离的话,那先要握一次手,由客户端保存住token。

4: 太小看黑客了,包都能抓到,token也能抓到,所以方法3也然并卵。

于是想一种办法,让黑客即使抓到包也看不懂,yes,就必须对关键信息进行加密。而且加密还得越复杂越好,让黑客逆向不出来。

加密的问题后面再说,参考(http://www.tuicool.com/articles/Zb6j6rR)的一种认证方法很好,

Api Key + Security Key + Sign

这里的认证逻辑即:

  1. 用户登录返回一个 api_key 和 security_key ;

  2. 然后客户端将 security_key 存在客户端;

  3. 当要发送请求之前,通过 function2 加密方法,把如图所示的五个值一起加密,得到一个 sign ;

  4. 发送请求的时候,则将除去 security_key 之外的值,以及 sign 一起发送给服务器端;

  5. 服务器端首先验证时间戳是否有效,比如是服务器时间戳5分钟之前的请求视为无效;

  6. 然后根据 api_key 验证 sercurity_key ;

  7. 最后验证 sign 。

是否需要加上时间戳验证?

上面的认证逻辑中加密得到签名的时候,把时间戳加进去是为了在一定程度上屏蔽了一些无效的请求,可以略去,也可以设计的更加严格。 如果想防止恶意的 api ddos 攻击,这一步验证肯定是不行的。需要做更多的验证,比如用户验证,ip 验证等。 可以参考 github 的 api 的设计 。它会在返回的 http 头信息里带上

X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4999

表示这个接口在某一时间段内,该授权用户调用该接口的最大次数为5000次,该时间段内还剩余4999次。当然,这样的验证加上之后,在代码的执行效率上肯定会有所影响。

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

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

血的教训,自己经历的一个实际案例:

一个取消用户喜欢的标签的接口,该接口会向服务器端发送类似于 ids=1,2,3,4 这样的 request_parameters ,然后服务器端拿到这些 id 之后切割,然后将该用户和这些标签的关系从 user_tag 表中删除。某个周末,数据库服务器报警,而依照我们用户习惯,那个时间不存在流量高峰,这个报警很不正常,正准备处理,报警结束了,但是过了一段时间就有用户反应他们喜欢的标签都被删了。

通过查询数据库的慢日志,发现有很多注入的 sql。

DELETE FROM `user_tag` WHERE uid=4385328 AND tid=1 OR 14=14;
DELETE FROM `user_tag` WHERE uid=4385328 AND tid=1 OR 91=91;

原来 没有对切割之后的 id 没有做数字验证,估计黑客就是传的 ids=1 OR 14=14,2,3 ,而一个 delete 操作可能超时,他丫的就搞了很多次请求,真是够狠的。

幸运,数据库还有定时的打包备份,大部分用户的数据还是恢复了,同时修复了这一漏洞。

所以如果这里将 request_parameters 也加入到签名之中,就减少了伪造请求的可能性,但是无法杜绝,破坏者可能就非要黑你,又对逆向工程非常熟悉,找到我们加密算法的实现,依然可以未知出合法的签名,所以我们常说,服务器端永远不能相信客户端的请求都是安全的、合法的,需要做验证的都还是不能省略。

同时这( sign 算法)也造成了 api 接口调试的成本,api 测试工具必须也得实现那一套算法,或者是设置在开发环境下不做验证。我们在配置开发环境的时候则是 vpn 连测试服务器所在内网,然后进行测试,否则开发环境也存在被人利用的风险。

 分割线--------------------------------------------------------------------------

好了,说实话,上面那位老兄的第六步没看太明白,根据APIkey check securitykey ,我理解securitykey 应该就是第一次握手生成的通常意义的token,

而这个APIkey则是类似于百度开发者那种key,是和用户绑定的,表示这个用户可以用我的api,每次请求都必须要有,

这个securitykey 是根据某种规则(加了时间戳作为salt),并且是基于APIkey生成的,这样才说的通。

那服务器端验证,先根据传过来的APIkey,生成securitykey,再和其他传过来的timestamp和request_parameters 和endpoint和前端采用同样的加密方法生成

一个sign,再和前端传过来的sign比较,一致就算pass,接下来就那securitykey 愉快地和服务器端(对称加密)消息通信啦。

黑客面临两个难点,一是要知道由APIkey生成securitykey的方法,二是要知道图中function2的加密算法,

然鹅,黑客如果在服务器端第一次给客户端APIkey和securitykey的时候就获取到它们两,而客户端的functions恰好又是js写的,那么这种方法也是然并卵的。

5:这个时候要讨论一下加密算法了。

对称加密(Symmetric Cryptography)

对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。

对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,不行的话就再用1解;但如果你的密钥有1 MB大,黑客们可能永远也无法破解,但加密和解密的过程要花费很长的时间。密钥的大小既要照顾到安全性,也要照顾到效率,是一个trade-off(权衡)。

非对称加密(Asymmetric Cryptography)

 非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。非对称加密使用这对密钥中的一个进行加密,而解密则需要另一个密钥。比如,你向银行请求公钥,银行将公钥发给你,你使用公钥对消息加密,那么只有私钥的持有人--银行才能对你的消息解密。与对称加密不同的是,银行不需要将私钥通过网络发送出去,因此安全性大大提高。

目前最常用的非对称加密算法是RSA算法,是Rivest, Shamir, 和Adleman于1978年发明,他们那时都是在MIT

虽然非对称加密很安全,但是和对称加密比起来,它非常的慢,所以我们还是要用对称加密来传送消息,但对称加密所使用的密钥我们可以通过非对称加密的方式发送出去。 所以,结合方法4和方法5,正常的握手流程应该是这样的。

(1) 用户登录返回一个 公钥(publickey),一个APIkey作为用户识别key。

(2) 浏览器生成了一个随机数作为对称密钥(securitykey ), 并用公钥对自己的对称密钥加密,浏览器将加密后的对称密钥发送给服务器。

(3) 服务器使用私钥解密得到浏览器的对称密钥。

(4) 两边可以使用对称密钥来对沟通的内容进行加密与解密了。

这招应该能让黑客傻眼了吧。但前提是用户名和密码可别泄漏了。

 

最后再说一下soap和rest的适用场景,

其实SOA本质就是一种网络函数调用,如果我们的需求都可以抽象成资源,就可以用rest,而且抽象得越精确越好,

个人感觉,如今大多数项目都是对某些数据(对象)CRUD,即使对与工作流等偏数据处理类的应用,也是一种活动或处理的调用而已,

验证,log,异常处理都可以交给spring,那么我想选择rest的根本原因还是在于它的高效率上吧。

 

以上是关于从resfful API设计到加密算法的主要内容,如果未能解决你的问题,请参考以下文章

确定从移动应用到 API 的 Post 请求的加密算法

resf规范

可以解密加密数据的片段吗?

分享2个Java转C#加密解密的算法

SpringCloud Gateway API接口安全设计(加密 签名)

SpringCloud Gateway API接口安全设计(加密 签名)